[Bf-blender-cvs] [a34761afc03] functions: Reduce wasted space in Function class
Jacques Lucke
noreply at git.blender.org
Tue May 28 12:13:29 CEST 2019
Commit: a34761afc03c1866928695c403b6b725615b6788
Author: Jacques Lucke
Date: Tue May 28 12:11:11 2019 +0200
Branches: functions
https://developer.blender.org/rBa34761afc03c1866928695c403b6b725615b6788
Reduce wasted space in Function class
This is achieved by storing strings in a single buffer instead
of using `std::string`, which does small object optimization
for every string individually. This optimization can be done
because all strings are known when the function is build and
don't change later on.
===================================================================
A source/blender/blenlib/BLI_chained_strings.hpp
M source/blender/blenlib/CMakeLists.txt
M source/blender/functions/core/function.cpp
M source/blender/functions/core/function.hpp
A tests/gtests/blenlib/BLI_chained_strings_test.cc
M tests/gtests/blenlib/CMakeLists.txt
===================================================================
diff --git a/source/blender/blenlib/BLI_chained_strings.hpp b/source/blender/blenlib/BLI_chained_strings.hpp
new file mode 100644
index 00000000000..01952ad8487
--- /dev/null
+++ b/source/blender/blenlib/BLI_chained_strings.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+/* These classes help storing multiple strings more compactly.
+ * This should only be used when:
+ * - All strings are freed at the same time.
+ * - The length of individual strings does not change.
+ * - All string lengths are known in the beginning. */
+
+#include "BLI_string_ref.hpp"
+#include "BLI_small_vector.hpp"
+
+namespace BLI {
+
+class ChainedStringRef {
+ uint32_t m_start : 24;
+ uint32_t m_size : 8;
+
+ public:
+ ChainedStringRef(uint start, uint size) : m_start(start), m_size(size)
+ {
+ BLI_assert(size < (1 << 8));
+ BLI_assert(start < (1 << 24));
+ }
+
+ uint size() const
+ {
+ return m_size;
+ }
+
+ StringRefNull to_string_ref(const char *ptr) const
+ {
+ return StringRefNull(ptr + m_start, m_size);
+ }
+};
+
+class ChainedStringsBuilder {
+ public:
+ ChainedStringRef add(StringRef str)
+ {
+ ChainedStringRef ref(m_chars.size(), str.size());
+ m_chars.extend(str.data(), str.size());
+ m_chars.append(0);
+ return ref;
+ }
+
+ char *build()
+ {
+ char *ptr = (char *)MEM_mallocN(m_chars.size(), __func__);
+ memcpy(ptr, m_chars.begin(), m_chars.size());
+ return ptr;
+ }
+
+ private:
+ SmallVector<char, 64> m_chars;
+};
+
+}; // namespace BLI
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index b6b4a3e7647..5eef0fe93bd 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -236,6 +236,7 @@ set(SRC
BLI_array_lookup.hpp
BLI_array_ref.hpp
+ BLI_chained_strings.hpp
BLI_composition.hpp
BLI_lazy_init.hpp
BLI_listbase_wrapper.hpp
diff --git a/source/blender/functions/core/function.cpp b/source/blender/functions/core/function.cpp
index 85c2543c4f8..e2d63c85619 100644
--- a/source/blender/functions/core/function.cpp
+++ b/source/blender/functions/core/function.cpp
@@ -2,6 +2,11 @@
namespace FN {
+Function::~Function()
+{
+ MEM_freeN((void *)m_strings);
+}
+
void Function::print()
{
std::cout << "Function: " << this->name() << std::endl;
@@ -26,20 +31,24 @@ FunctionBuilder::FunctionBuilder()
void FunctionBuilder::add_input(StringRef name, SharedType &type)
{
- m_input_names.append(name.to_std_string());
+ auto ref = m_strings_builder.add(name);
+ m_input_names.append(ref);
m_input_types.append(type);
}
void FunctionBuilder::add_output(StringRef name, SharedType &type)
{
- m_output_names.append(name.to_std_string());
+ auto ref = m_strings_builder.add(name);
+ m_output_names.append(ref);
m_output_types.append(type);
}
SharedFunction FunctionBuilder::build(StringRef function_name)
{
+ auto name_ref = m_strings_builder.add(function_name);
+ char *strings = m_strings_builder.build();
return SharedFunction::New(
- function_name, m_input_names, m_input_types, m_output_names, m_output_types);
+ name_ref, m_input_names, m_input_types, m_output_names, m_output_types, strings);
}
} /* namespace FN */
diff --git a/source/blender/functions/core/function.hpp b/source/blender/functions/core/function.hpp
index dd33846852b..d015dd29199 100644
--- a/source/blender/functions/core/function.hpp
+++ b/source/blender/functions/core/function.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "type.hpp"
+#include "BLI_chained_strings.hpp"
namespace FN {
@@ -38,26 +39,28 @@ class Function final : public RefCountedBase {
public:
Function(Function &fn) = delete;
- Function(StringRef name,
- ArrayRef<std::string> input_names,
+ Function(ChainedStringRef name,
+ ArrayRef<ChainedStringRef> input_names,
ArrayRef<SharedType> input_types,
- ArrayRef<std::string> output_names,
- ArrayRef<SharedType> output_types)
- : m_name(name.to_std_string()),
+ ArrayRef<ChainedStringRef> output_names,
+ ArrayRef<SharedType> output_types,
+ const char *strings)
+ : m_name(name),
m_input_names(input_names.to_small_vector()),
m_input_types(input_types.to_small_vector()),
m_output_names(output_names.to_small_vector()),
- m_output_types(output_types.to_small_vector())
+ m_output_types(output_types.to_small_vector()),
+ m_strings(strings)
{
BLI_assert(m_input_names.size() == m_input_types.size());
BLI_assert(m_output_names.size() == m_output_types.size());
}
- ~Function() = default;
+ ~Function();
const StringRefNull name() const
{
- return m_name;
+ return m_name.to_string_ref(m_strings);
}
template<typename T> inline bool has_body() const
@@ -120,12 +123,12 @@ class Function final : public RefCountedBase {
StringRefNull input_name(uint index)
{
- return m_input_names[index];
+ return m_input_names[index].to_string_ref(m_strings);
}
StringRefNull output_name(uint index)
{
- return m_output_names[index];
+ return m_output_names[index].to_string_ref(m_strings);
}
template<typename T> SmallVector<T *> input_extensions() const
@@ -161,14 +164,16 @@ class Function final : public RefCountedBase {
}
private:
- const std::string m_name;
+ ChainedStringRef m_name;
Composition m_bodies;
mutable std::mutex m_body_mutex;
- SmallVector<std::string> m_input_names;
+ SmallVector<ChainedStringRef> m_input_names;
SmallVector<SharedType> m_input_types;
- SmallVector<std::string> m_output_names;
+ SmallVector<ChainedStringRef> m_output_names;
SmallVector<SharedType> m_output_types;
+
+ const char *m_strings;
};
using SharedFunction = AutoRefCount<Function>;
@@ -176,9 +181,10 @@ using FunctionPerType = SmallMap<SharedType, SharedFunction>;
class FunctionBuilder {
private:
- SmallVector<std::string> m_input_names;
+ ChainedStringsBuilder m_strings_builder;
+ SmallVector<ChainedStringRef> m_input_names;
SmallVector<SharedType> m_input_types;
- SmallVector<std::string> m_output_names;
+ SmallVector<ChainedStringRef> m_output_names;
SmallVector<SharedType> m_output_types;
public:
diff --git a/tests/gtests/blenlib/BLI_chained_strings_test.cc b/tests/gtests/blenlib/BLI_chained_strings_test.cc
new file mode 100644
index 00000000000..ec0ef8691cb
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_chained_strings_test.cc
@@ -0,0 +1,46 @@
+#include "testing/testing.h"
+#include "BLI_chained_strings.hpp"
+
+using BLI::ChainedStringRef;
+using BLI::ChainedStringsBuilder;
+
+TEST(chained_strings, BuildEmpty)
+{
+ ChainedStringsBuilder builder;
+ char *str = builder.build();
+ EXPECT_NE(str, nullptr);
+ MEM_freeN(str);
+}
+
+TEST(chained_strings, BuildSingleString)
+{
+ ChainedStringsBuilder builder;
+ auto ref = builder.add("Hello");
+
+ char *str = builder.build();
+
+ EXPECT_EQ(ref.size(), 5);
+ EXPECT_EQ(ref.to_string_ref(str), "Hello");
+
+ MEM_freeN(str);
+}
+
+TEST(chained_strings, BuildMultiple)
+{
+ ChainedStringsBuilder builder;
+ auto ref1 = builder.add("Why");
+ auto ref2 = builder.add("What");
+ auto ref3 = builder.add("Where");
+
+ char *str = builder.build();
+
+ EXPECT_EQ(ref1.size(), 3);
+ EXPECT_EQ(ref2.size(), 4);
+ EXPECT_EQ(ref3.size(), 5);
+
+ EXPECT_EQ(ref1.to_string_ref(str), "Why");
+ EXPECT_EQ(ref2.to_string_ref(str), "What");
+ EXPECT_EQ(ref3.to_string_ref(str), "Where");
+
+ MEM_freeN(str);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 477a99938ee..4e8fe21d0ff 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -42,6 +42,7 @@ BLENDER_TEST(BLI_array_lookup "bf_blenlib")
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_array_ref "bf_blenlib")
+BLENDER_TEST(BLI_chained_strings "bf_blenlib")
BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_edgehash "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
More information about the Bf-blender-cvs
mailing list