Cleanup: avoid static initialization order issues when accessing CPPTypes

Instead of depending on static initialization order of globals use
static variables within functions. Those are initialized on first use.
This is every so slighly less efficient, but avoids a full class of problems.
This commit is contained in:
Jacques Lucke 2020-07-17 14:15:06 +02:00
parent 3ef59121a4
commit 2679236047
13 changed files with 35 additions and 94 deletions

@ -54,7 +54,6 @@
#include "BLT_translation.h"
#include "FN_attributes_ref.hh"
#include "FN_cpp_types.hh"
#include "FN_multi_function_network_evaluation.hh"
#include "FN_multi_function_network_optimization.hh"

@ -38,7 +38,6 @@ set(SRC
FN_array_spans.hh
FN_attributes_ref.hh
FN_cpp_type.hh
FN_cpp_types.hh
FN_generic_vector_array.hh
FN_multi_function.hh
FN_multi_function_builder.hh

@ -788,15 +788,12 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
} // namespace blender::fn
#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \
static TYPE_NAME default_value_##IDENTIFIER; \
static std::unique_ptr<const blender::fn::CPPType> CPPTYPE_##IDENTIFIER##_owner = \
blender::fn::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \
const blender::fn::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \
template<> const blender::fn::CPPType &blender::fn::CPPType::get<TYPE_NAME>() \
{ \
/* This can happen when trying to access a CPPType during static storage initialization. */ \
BLI_assert(CPPTYPE_##IDENTIFIER##_owner.get() != nullptr); \
return CPPType_##IDENTIFIER; \
static TYPE_NAME default_value; \
static std::unique_ptr<const CPPType> cpp_type = blender::fn::create_cpp_type<TYPE_NAME>( \
STRINGIFY(IDENTIFIER), default_value); \
return *cpp_type; \
}
#endif /* __FN_CPP_TYPE_HH__ */

@ -1,48 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __FN_CPP_TYPES_HH__
#define __FN_CPP_TYPES_HH__
/** \file
* \ingroup fn
*
* This header provides convenient access to CPPType instances for some core types like integer
* types.
*/
#include "FN_cpp_type.hh"
namespace blender::fn {
extern const CPPType &CPPType_bool;
extern const CPPType &CPPType_float;
extern const CPPType &CPPType_float3;
extern const CPPType &CPPType_float4x4;
extern const CPPType &CPPType_int32;
extern const CPPType &CPPType_uint32;
extern const CPPType &CPPType_uint8;
extern const CPPType &CPPType_Color4f;
extern const CPPType &CPPType_Color4b;
extern const CPPType &CPPType_string;
} // namespace blender::fn
#endif /* __FN_CPP_TYPES_HH__ */

@ -14,7 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "FN_cpp_types.hh"
#include "FN_cpp_type.hh"
#include "BLI_color.hh"
#include "BLI_float2.hh"

@ -34,7 +34,6 @@
#include "NOD_node_tree_multi_function.hh"
#include "FN_attributes_ref.hh"
#include "FN_cpp_types.hh"
#include "FN_multi_function_network_evaluation.hh"
#include "FN_multi_function_network_optimization.hh"
@ -108,7 +107,7 @@ static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes(
Array<std::string> attribute_names{amount, NoInitialization()};
for (uint i : IndexRange(amount)) {
params.add_uninitialized_single_output(
fn::GMutableSpan(fn::CPPType_string, attribute_names.data() + i, 1));
fn::GMutableSpan(fn::CPPType::get<std::string>(), attribute_names.data() + i, 1));
}
fn::MFContextBuilder context;

@ -3,7 +3,6 @@
#include "testing/testing.h"
#include "FN_array_spans.hh"
#include "FN_cpp_types.hh"
#include "FN_generic_vector_array.hh"
#include "BLI_array.hh"
@ -77,7 +76,7 @@ TEST(virtual_array_span, MultipleArrayConstructor)
TEST(generic_virtual_array_span, TypeConstructor)
{
GVArraySpan span{CPPType_int32};
GVArraySpan span{CPPType::get<int32_t>()};
EXPECT_EQ(span.size(), 0);
EXPECT_TRUE(span.is_empty());
@ -88,7 +87,7 @@ TEST(generic_virtual_array_span, TypeConstructor)
TEST(generic_virtual_array_span, GSpanConstructor)
{
std::array<std::string, 3> values = {"hello", "world", "test"};
GVArraySpan span{GSpan(CPPType_string, values.data(), 3), 5};
GVArraySpan span{GSpan(CPPType::get<std::string>(), values.data(), 3), 5};
EXPECT_EQ(span.size(), 5);
EXPECT_FALSE(span.is_empty());
EXPECT_EQ(span[0][0], values.data());
@ -119,7 +118,7 @@ TEST(generic_virtual_array_span, IsSingleArray1)
TEST(generic_virtual_array_span, IsSingleArray2)
{
GVectorArray vectors{CPPType_int32, 3};
GVectorArray vectors{CPPType::get<int32_t>(), 3};
GVectorArrayRef<int> vectors_ref = vectors;
vectors_ref.append(1, 4);

@ -2,7 +2,6 @@
#include "BLI_float3.hh"
#include "FN_attributes_ref.hh"
#include "FN_cpp_types.hh"
#include "testing/testing.h"

@ -3,7 +3,6 @@
#include "testing/testing.h"
#include "FN_cpp_type.hh"
#include "FN_cpp_types.hh"
namespace blender::fn {
@ -76,6 +75,8 @@ struct TestType {
MAKE_CPP_TYPE(TestType, TestType)
const CPPType &CPPType_TestType = CPPType::get<TestType>();
TEST(cpp_type, Size)
{
EXPECT_EQ(CPPType_TestType.size(), sizeof(TestType));
@ -312,7 +313,7 @@ TEST(cpp_type, DebugPrint)
{
int value = 42;
std::stringstream ss;
CPPType_int32.debug_print((void *)&value, ss);
CPPType::get<int32_t>().debug_print((void *)&value, ss);
std::string text = ss.str();
EXPECT_EQ(text, "42");
}

@ -1,6 +1,5 @@
/* Apache License, Version 2.0 */
#include "FN_cpp_types.hh"
#include "FN_generic_vector_array.hh"
#include "testing/testing.h"
@ -9,19 +8,19 @@ namespace blender::fn {
TEST(generic_vector_array, Constructor)
{
GVectorArray vectors{CPPType_int32, 3};
GVectorArray vectors{CPPType::get<int32_t>(), 3};
EXPECT_EQ(vectors.size(), 3);
EXPECT_EQ(vectors.lengths().size(), 3);
EXPECT_EQ(vectors.starts().size(), 3);
EXPECT_EQ(vectors.lengths()[0], 0);
EXPECT_EQ(vectors.lengths()[1], 0);
EXPECT_EQ(vectors.lengths()[2], 0);
EXPECT_EQ(vectors.type(), CPPType_int32);
EXPECT_EQ(vectors.type(), CPPType::get<int32_t>());
}
TEST(generic_vector_array, Append)
{
GVectorArray vectors{CPPType_string, 3};
GVectorArray vectors{CPPType::get<std::string>(), 3};
std::string value = "hello";
vectors.append(0, &value);
value = "world";
@ -39,7 +38,7 @@ TEST(generic_vector_array, Append)
TEST(generic_vector_array, AsArraySpan)
{
GVectorArray vectors{CPPType_int32, 3};
GVectorArray vectors{CPPType::get<int32_t>(), 3};
int value = 3;
vectors.append(0, &value);
vectors.append(0, &value);
@ -49,7 +48,7 @@ TEST(generic_vector_array, AsArraySpan)
vectors.append(2, &value);
GVArraySpan span = vectors;
EXPECT_EQ(span.type(), CPPType_int32);
EXPECT_EQ(span.type(), CPPType::get<int32_t>());
EXPECT_EQ(span.size(), 3);
EXPECT_EQ(span[0].size(), 2);
EXPECT_EQ(span[1].size(), 0);
@ -60,7 +59,7 @@ TEST(generic_vector_array, AsArraySpan)
TEST(generic_vector_array, TypedRef)
{
GVectorArray vectors{CPPType_int32, 4};
GVectorArray vectors{CPPType::get<int32_t>(), 4};
GVectorArrayRef<int> ref = vectors.typed<int>();
ref.append(0, 2);
ref.append(0, 6);
@ -84,7 +83,7 @@ TEST(generic_vector_array, TypedRef)
TEST(generic_vector_array, Extend)
{
GVectorArray vectors{CPPType_int32, 3};
GVectorArray vectors{CPPType::get<int32_t>(), 3};
GVectorArrayRef<int> ref = vectors;
ref.extend(1, {5, 6, 7});

@ -2,7 +2,6 @@
#include "testing/testing.h"
#include "FN_cpp_types.hh"
#include "FN_multi_function_builder.hh"
#include "FN_multi_function_network.hh"
#include "FN_multi_function_network_evaluation.hh"
@ -195,7 +194,7 @@ TEST(multi_function_network, Test2)
Array<int> input_value_1 = {3, 6};
int input_value_2 = 4;
GVectorArray output_value_1(CPPType_int32, 5);
GVectorArray output_value_1(CPPType::get<int32_t>(), 5);
Array<int> output_value_2(5, -1);
MFParamsBuilder params(network_fn, 5);
@ -221,14 +220,14 @@ TEST(multi_function_network, Test2)
EXPECT_EQ(output_value_2[4], 39);
}
{
GVectorArray input_value_1(CPPType_int32, 3);
GVectorArray input_value_1(CPPType::get<int32_t>(), 3);
GVectorArrayRef<int> input_value_ref_1 = input_value_1;
input_value_ref_1.extend(0, {3, 4, 5});
input_value_ref_1.extend(1, {1, 2});
Array<int> input_value_2 = {4, 2, 3};
GVectorArray output_value_1(CPPType_int32, 3);
GVectorArray output_value_1(CPPType::get<int32_t>(), 3);
Array<int> output_value_2(3, -1);
MFParamsBuilder params(network_fn, 3);

@ -2,7 +2,6 @@
#include "testing/testing.h"
#include "FN_cpp_types.hh"
#include "FN_multi_function.hh"
#include "FN_multi_function_builder.hh"
@ -126,7 +125,7 @@ TEST(multi_function, CreateRangeFunction)
{
CreateRangeFunction fn;
GVectorArray ranges(CPPType_uint32, 5);
GVectorArray ranges(CPPType::get<int32_t>(), 5);
GVectorArrayRef<uint> ranges_ref(ranges);
Array<uint> sizes = {3, 0, 6, 1, 4};
@ -173,9 +172,9 @@ class GenericAppendFunction : public MultiFunction {
TEST(multi_function, GenericAppendFunction)
{
GenericAppendFunction fn(CPPType_int32);
GenericAppendFunction fn(CPPType::get<int32_t>());
GVectorArray vectors(CPPType_int32, 4);
GVectorArray vectors(CPPType::get<int32_t>(), 4);
GVectorArrayRef<int> vectors_ref(vectors);
vectors_ref.append(0, 1);
vectors_ref.append(0, 2);
@ -318,7 +317,7 @@ TEST(multi_function, CustomMF_Constant)
TEST(multi_function, CustomMF_GenericConstant)
{
int value = 42;
CustomMF_GenericConstant fn{CPPType_int32, (const void *)&value};
CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value};
EXPECT_EQ(fn.param_name(0), "42");
Array<int> outputs(4, 0);
@ -342,7 +341,7 @@ TEST(multi_function, CustomMF_GenericConstantArray)
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
GVectorArray g_vector_array{CPPType_int32, 4};
GVectorArray g_vector_array{CPPType::get<int32_t>(), 4};
GVectorArrayRef<int> vector_array = g_vector_array;
MFParamsBuilder params(fn, g_vector_array.size());

@ -2,14 +2,13 @@
#include "testing/testing.h"
#include "FN_cpp_types.hh"
#include "FN_spans.hh"
namespace blender::fn {
TEST(generic_span, TypeConstructor)
{
GSpan span(CPPType_float);
GSpan span(CPPType::get<float>());
EXPECT_EQ(span.size(), 0);
EXPECT_EQ(span.typed<float>().size(), 0);
EXPECT_TRUE(span.is_empty());
@ -19,7 +18,7 @@ TEST(generic_span, BufferAndSizeConstructor)
{
int values[4] = {6, 7, 3, 2};
void *buffer = (void *)values;
GSpan span(CPPType_int32, buffer, 4);
GSpan span(CPPType::get<int32_t>(), buffer, 4);
EXPECT_EQ(span.size(), 4);
EXPECT_FALSE(span.is_empty());
EXPECT_EQ(span.typed<int>().size(), 4);
@ -31,7 +30,7 @@ TEST(generic_span, BufferAndSizeConstructor)
TEST(generic_mutable_span, TypeConstructor)
{
GMutableSpan span(CPPType_int32);
GMutableSpan span(CPPType::get<int32_t>());
EXPECT_EQ(span.size(), 0);
EXPECT_TRUE(span.is_empty());
}
@ -40,7 +39,7 @@ TEST(generic_mutable_span, BufferAndSizeConstructor)
{
int values[4] = {4, 7, 3, 5};
void *buffer = (void *)values;
GMutableSpan span(CPPType_int32, buffer, 4);
GMutableSpan span(CPPType::get<int32_t>(), buffer, 4);
EXPECT_EQ(span.size(), 4);
EXPECT_FALSE(span.is_empty());
EXPECT_EQ(span.typed<int>().size(), 4);
@ -127,7 +126,7 @@ TEST(virtual_span, SingleConstructor)
TEST(generic_virtual_span, TypeConstructor)
{
GVSpan span(CPPType_int32);
GVSpan span(CPPType::get<int32_t>());
EXPECT_EQ(span.size(), 0);
EXPECT_TRUE(span.is_empty());
EXPECT_FALSE(span.is_single_element());
@ -139,7 +138,7 @@ TEST(generic_virtual_span, TypeConstructor)
TEST(generic_virtual_span, GenericSpanConstructor)
{
int values[4] = {3, 4, 5, 6};
GVSpan span{GSpan(CPPType_int32, values, 4)};
GVSpan span{GSpan(CPPType::get<int32_t>(), values, 4)};
EXPECT_EQ(span.size(), 4);
EXPECT_FALSE(span.is_empty());
EXPECT_EQ(span[0], &values[0]);
@ -167,7 +166,7 @@ TEST(generic_virtual_span, SpanConstructor)
{
std::array<int, 3> values = {6, 7, 8};
GVSpan span{Span<int>(values)};
EXPECT_EQ(span.type(), CPPType_int32);
EXPECT_EQ(span.type(), CPPType::get<int32_t>());
EXPECT_EQ(span.size(), 3);
EXPECT_EQ(span[0], &values[0]);
EXPECT_EQ(span[1], &values[1]);
@ -190,7 +189,7 @@ TEST(generic_virtual_span, SpanConstructor)
TEST(generic_virtual_span, SingleConstructor)
{
int value = 5;
GVSpan span = GVSpan::FromSingle(CPPType_int32, &value, 3);
GVSpan span = GVSpan::FromSingle(CPPType::get<int32_t>(), &value, 3);
EXPECT_EQ(span.size(), 3);
EXPECT_FALSE(span.is_empty());
EXPECT_EQ(span[0], &value);