diff options
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r-- | source/blender/blenlib/BLI_enumerable_thread_specific.hh | 73 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_fileops.h | 2 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_hash.hh | 22 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_linear_allocator.hh | 15 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_map.hh | 31 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_vector_set.hh | 32 | ||||
-rw-r--r-- | source/blender/blenlib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/blenlib/intern/storage.c | 3 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_linear_allocator_test.cc | 13 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_map_test.cc | 13 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_vector_set_test.cc | 13 |
11 files changed, 213 insertions, 5 deletions
diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh new file mode 100644 index 00000000000..89be4cad848 --- /dev/null +++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#pragma once + +#ifdef WITH_TBB +# include <tbb/enumerable_thread_specific.h> +#endif + +#include <atomic> +#include <mutex> + +#include "BLI_map.hh" +#include "BLI_utility_mixins.hh" + +namespace blender { + +namespace enumerable_thread_specific_utils { +inline std::atomic<int> next_id = 0; +inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed); +} // namespace enumerable_thread_specific_utils + +/** + * This is mainly a wrapper for `tbb::enumerable_thread_specific`. The wrapper is needed because we + * want to be able to build without tbb. + * + * More features of the tbb version can be wrapped when they are used. + */ +template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable { +#ifdef WITH_TBB + + private: + tbb::enumerable_thread_specific<T> values_; + + public: + T &local() + { + return values_.local(); + } + +#else /* WITH_TBB */ + + private: + std::mutex mutex_; + /* Maps thread ids to their corresponding values. The values are not embedded in the map, so that + * their addresses do not change when the map grows. */ + Map<int, std::unique_ptr<T>> values_; + + public: + T &local() + { + const int thread_id = enumerable_thread_specific_utils::thread_id; + std::lock_guard lock{mutex_}; + return *values_.lookup_or_add_cb(thread_id, []() { return std::make_unique<T>(); }); + } + +#endif /* WITH_TBB */ +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index df80e720363..bf18dd1070e 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -87,7 +87,7 @@ typedef enum eFileAttributes { FILE_ATTR_RESTRICTED = 1 << 6, /* Protected by OS. */ FILE_ATTR_TEMPORARY = 1 << 7, /* Used for temporary storage. */ FILE_ATTR_SPARSE_FILE = 1 << 8, /* Sparse File. */ - FILE_ATTR_OFFLINE = 1 << 9, /* Data is not immediately available. */ + FILE_ATTR_OFFLINE = 1 << 9, /* Contents available after a short delay. */ FILE_ATTR_ALIAS = 1 << 10, /* Mac Alias or Windows LNK. File-based redirection. */ FILE_ATTR_REPARSE_POINT = 1 << 11, /* File has associated re-parse point. */ FILE_ATTR_SYMLINK = 1 << 12, /* Reference to another file. */ diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 4022c2baa1f..fbed321534c 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -85,9 +85,12 @@ namespace blender { /** - * If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on - * the value. If there is no such method, this will result in a compiler error. Usually that means - * that you have to implement a hash function using one of three strategies listed above. + * If there is no other specialization of #DefaultHash for a given type, look for a hash function + * on the type itself. Implementing a `hash()` method on a type is often significantly easier than + * specializing #DefaultHash. + * + * To support heterogeneous lookup, a type can also implement a static `hash_as(const OtherType &)` + * function. * * In the case of an enum type, the default hash is just to cast the enum value to an integer. */ @@ -95,12 +98,25 @@ template<typename T> struct DefaultHash { uint64_t operator()(const T &value) const { if constexpr (std::is_enum_v<T>) { + /* For enums use the value as hash directly. */ return (uint64_t)value; } else { + /* Try to call the `hash()` function on the value. */ + /* If this results in a compiler error, no hash function for the type has been found. */ return value.hash(); } } + + template<typename U> uint64_t operator()(const U &value) const + { + /* Try calling the static `T::hash_as(value)` function with the given value. The returned hash + * should be "compatible" with `T::hash()`. Usually that means that if `value` is converted to + * `T` its hash does not change. */ + /* If this results in a compiler error, no hash function for the heterogeneous lookup has been + * found. */ + return T::hash_as(value); + } }; /** diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index bd883c1de16..87361d412cb 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -149,6 +149,21 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya } /** + * Construct multiple instances of a type in an array. The constructor of is called with the + * given arguments. The caller is responsible for calling the destructor (and not `delete`) on + * the constructed elements. + */ + template<typename T, typename... Args> + MutableSpan<T> construct_array(int64_t size, Args &&... args) + { + MutableSpan<T> array = this->allocate_array<T>(size); + for (const int64_t i : IndexRange(size)) { + new (&array[i]) T(std::forward<Args>(args)...); + } + return array; + } + + /** * Copy the given array into a memory buffer provided by this allocator. */ template<typename T> MutableSpan<T> construct_array_copy(Span<T> src) diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index 95afbfc2ec6..4d254960f34 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -605,6 +605,37 @@ class Map { } /** + * Returns the key that is stored in the set that compares equal to the given key. This invokes + * undefined behavior when the key is not in the map. + */ + const Key &lookup_key(const Key &key) const + { + return this->lookup_key_as(key); + } + template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const + { + const Slot &slot = this->lookup_slot(key, hash_(key)); + return *slot.key(); + } + + /** + * Returns a pointer to the key that is stored in the map that compares equal to the given key. + * If the key is not in the map, null is returned. + */ + const Key *lookup_key_ptr(const Key &key) const + { + return this->lookup_key_ptr_as(key); + } + template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const + { + const Slot *slot = this->lookup_slot_ptr(key, hash_(key)); + if (slot == nullptr) { + return nullptr; + } + return slot->key(); + } + + /** * Calls the provided callback for every key-value-pair in the map. The callback is expected * to take a `const Key &` as first and a `const Value &` as second parameter. */ diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index 2f5d04aefa2..567e4fd8128 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -415,6 +415,38 @@ class VectorSet { } /** + * Returns the key that is stored in the vector set that compares equal to the given key. This + * invokes undefined behavior when the key is not in the set. + */ + const Key &lookup_key(const Key &key) const + { + return this->lookup_key_as(key); + } + template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const + { + const Key *key_ptr = this->lookup_key_ptr_as(key); + BLI_assert(key_ptr != nullptr); + return *key_ptr; + } + + /** + * Returns a pointer to the key that is stored in the vector set that compares equal to the given + * key. If the key is not in the set, null is returned. + */ + const Key *lookup_key_ptr(const Key &key) const + { + return this->lookup_key_ptr_as(key); + } + template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const + { + const int64_t index = this->index_of_try__impl(key, hash_(key)); + if (index >= 0) { + return keys_ + index; + } + return nullptr; + } + + /** * Get a pointer to the beginning of the array containing all keys. */ const Key *data() const diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 06f937ce5ca..c8436b6b9cc 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -186,6 +186,7 @@ set(SRC BLI_edgehash.h BLI_endian_switch.h BLI_endian_switch_inline.h + BLI_enumerable_thread_specific.hh BLI_expr_pylike_eval.h BLI_fileops.h BLI_fileops_types.h diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index cb2634e6fda..5f823396ed9 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -266,7 +266,8 @@ eFileAttributes BLI_file_attributes(const char *path) if (attr & FILE_ATTRIBUTE_SPARSE_FILE) { ret |= FILE_ATTR_SPARSE_FILE; } - if (attr & FILE_ATTRIBUTE_OFFLINE) { + if (attr & FILE_ATTRIBUTE_OFFLINE || attr & FILE_ATTRIBUTE_RECALL_ON_OPEN || + attr & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS) { ret |= FILE_ATTR_OFFLINE; } if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc index 977e5dba497..0e0145e592a 100644 --- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc +++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc @@ -136,4 +136,17 @@ TEST(linear_allocator, ManyAllocations) } } +TEST(linear_allocator, ConstructArray) +{ + LinearAllocator<> allocator; + MutableSpan<std::string> strings = allocator.construct_array<std::string>(4, "hello"); + EXPECT_EQ(strings[0], "hello"); + EXPECT_EQ(strings[1], "hello"); + EXPECT_EQ(strings[2], "hello"); + EXPECT_EQ(strings[3], "hello"); + for (std::string &string : strings) { + string.~basic_string(); + } +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc index 18be456bd20..679a10e9ce0 100644 --- a/source/blender/blenlib/tests/BLI_map_test.cc +++ b/source/blender/blenlib/tests/BLI_map_test.cc @@ -640,6 +640,19 @@ TEST(map, RemoveDuringIteration) EXPECT_EQ(map.lookup(3), 3); } +TEST(map, LookupKey) +{ + Map<std::string, int> map; + map.add("a", 0); + map.add("b", 1); + map.add("c", 2); + EXPECT_EQ(map.lookup_key("a"), "a"); + EXPECT_EQ(map.lookup_key_as("c"), "c"); + EXPECT_EQ(map.lookup_key_ptr_as("d"), nullptr); + EXPECT_EQ(map.lookup_key_ptr_as("b")->size(), 1); + EXPECT_EQ(map.lookup_key_ptr("a"), map.lookup_key_ptr_as("a")); +} + /** * Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot. */ diff --git a/source/blender/blenlib/tests/BLI_vector_set_test.cc b/source/blender/blenlib/tests/BLI_vector_set_test.cc index c535ac57774..c4016ca75e1 100644 --- a/source/blender/blenlib/tests/BLI_vector_set_test.cc +++ b/source/blender/blenlib/tests/BLI_vector_set_test.cc @@ -258,4 +258,17 @@ TEST(vector_set, Clear) EXPECT_EQ(set.size(), 0); } +TEST(vector_set, LookupKey) +{ + VectorSet<std::string> set; + set.add("a"); + set.add("b"); + set.add("c"); + EXPECT_EQ(set.lookup_key("a"), "a"); + EXPECT_EQ(set.lookup_key_as("c"), "c"); + EXPECT_EQ(set.lookup_key_ptr_as("d"), nullptr); + EXPECT_EQ(set.lookup_key_ptr_as("b")->size(), 1); + EXPECT_EQ(set.lookup_key_ptr("a"), set.lookup_key_ptr_as("a")); +} + } // namespace blender::tests |