remove a bunch of <functional> includes

This forces us to use an explicit hash class in a few place, but it
is cleaner.

remove utils::lower_bound and utils::upper_bound, which were not used.
This commit is contained in:
Mathias Agopian
2022-06-03 08:35:57 -07:00
committed by Mathias Agopian
parent 991fa0cf7d
commit 718e7ab064
24 changed files with 69 additions and 326 deletions
+1
View File
@@ -7,6 +7,7 @@ A new header is inserted each time a *tag* is created.
- gltfio: fix morphing for un-packed accessors
- engine: disable user scissor while rendering the Shadow Maps (#5607)
- utils: remove `std::hash<T>` definitions for `libutils` types. Use `T::Hasher` explicitly instead. [⚠️ **API Change**]
## v1.23.1
@@ -26,6 +26,8 @@
#include <utils/compiler.h>
#include <functional>
#include <stdint.h>
// Command debugging off. debugging virtuals are not called.
@@ -17,17 +17,18 @@
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H
#define TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H
#include <array>
#include <stddef.h>
#include <utils/compiler.h>
#include <utils/bitset.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
namespace filament {
namespace backend {
#include <array>
#include <memory>
#include <stddef.h>
namespace filament::backend {
class SamplerGroup {
public:
@@ -151,7 +152,6 @@ private:
mutable utils::bitset32 mDirty;
};
} // namespace backend
} // namespace filament
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H
+6 -1
View File
@@ -316,7 +316,12 @@ private:
mutable bool mHasMaterial{};
};
tsl::robin_map<utils::StaticString, PostProcessMaterial> mMaterialRegistry;
using MaterialRegistryMap = tsl::robin_map<
utils::StaticString,
PostProcessMaterial,
utils::StaticString::Hasher>;
MaterialRegistryMap mMaterialRegistry;
void registerPostProcessMaterial(utils::StaticString name, uint8_t const* data, int size);
PostProcessMaterial& getPostProcessMaterial(utils::StaticString name) noexcept;
+2 -2
View File
@@ -72,8 +72,8 @@ private:
bool hasProperty(const char* name) const noexcept;
void* getPropertyAddress(const char* name) noexcept;
DataSource getDataSource(const char* name) const noexcept;
std::unordered_map<utils::StaticString, void*> mPropertyMap;
std::unordered_map<utils::StaticString, DataSource> mDataSourceMap;
std::unordered_map<utils::StaticString, void*, utils::StaticString::Hasher> mPropertyMap;
std::unordered_map<utils::StaticString, DataSource, utils::StaticString::Hasher> mDataSourceMap;
};
FILAMENT_UPCAST(DebugRegistry)
+1 -1
View File
@@ -208,7 +208,7 @@ private:
* (a vector<> could work, but removes would be O(n)). robin_set<> iterates almost as
* nicely as vector<>, which is a good compromise.
*/
tsl::robin_set<utils::Entity> mEntities;
tsl::robin_set<utils::Entity, utils::Entity::Hasher> mEntities;
/*
+4 -1
View File
@@ -26,7 +26,10 @@
namespace filament {
class Blackboard {
using Container = std::unordered_map<utils::StaticString, FrameGraphHandle>;
using Container = std::unordered_map<
utils::StaticString,
FrameGraphHandle,
utils::StaticString::Hasher>;
public:
Blackboard() noexcept;
@@ -63,7 +63,7 @@ public:
void unregisterAll();
std::size_t numRegistered() const noexcept;
size_t numRegistered() const noexcept;
void getRegisteredMaterials(filament::MaterialInstance** materialList,
utils::CString* materialNameList) const;
+2 -2
View File
@@ -118,8 +118,8 @@ private:
TextureNode* getStatus(filament::Texture* texture);
// The following maps contain the directed edges in the graph.
tsl::robin_map<Entity, EntityNode> mEntityToMaterial;
tsl::robin_map<Material*, tsl::robin_set<Entity>> mMaterialToEntity;
tsl::robin_map<Entity, EntityNode, Entity::Hasher> mEntityToMaterial;
tsl::robin_map<Material*, tsl::robin_set<Entity, Entity::Hasher>> mMaterialToEntity;
tsl::robin_map<Material*, MaterialNode> mMaterialToTexture;
tsl::robin_map<filament::Texture*, tsl::robin_set<Material*>> mTextureToMaterial;
+1 -1
View File
@@ -55,7 +55,7 @@ struct Skin {
// The set of all nodes that are influenced by this skin.
// This is initially gleaned from the glTF file using the "skin" attribute of each node.
tsl::robin_set<utils::Entity> targets;
tsl::robin_set<utils::Entity, utils::Entity::Hasher> targets;
};
struct VariantMapping {
+1 -1
View File
@@ -364,7 +364,7 @@ uint32_t getMipmapCount(const LinearImage& source) {
Filter filterFromString(const char* rawname) {
using namespace utils;
using std::unordered_map;
static const unordered_map<StaticString, Filter> map = {
static const unordered_map<StaticString, Filter, StaticString::Hasher> map = {
{ "BOX", Filter::BOX},
{ "NEAREST", Filter::NEAREST},
{ "HERMITE", Filter::HERMITE},
@@ -16,14 +16,12 @@
#include "PerformanceCounters.h"
#include <utils/algorithm.h>
#include <utils/compiler.h>
#include <benchmark/benchmark.h>
#include <random>
#include <vector>
#include <iostream>
using namespace utils;
@@ -95,70 +93,5 @@ BENCHMARK_DEFINE_F(BinarySearch, stdLowerBound)(benchmark::State& state) {
}
}
BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBound)(benchmark::State& state) {
auto first = data.begin();
auto last = data.begin() + state.range(0);
std::vector<value_type> indices = prepareItems(state.range(0));
value_type const* ip = indices.data();
size_t i = 0;
{
PerformanceCounters pc(state);
for (auto _ : state) {
auto item = ip[i++ % state.range(0)];
auto const& pos = utils::lower_bound(first, last, item);
benchmark::DoNotOptimize(pos);
}
}
}
BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBoundPOT)(benchmark::State& state) {
auto first = data.begin();
auto last = data.begin() + state.range(0);
std::vector<value_type> indices = prepareItems(state.range(0));
value_type const* ip = indices.data();
size_t i = 0;
{
PerformanceCounters pc(state);
for (auto _ : state) {
auto item = ip[i++ % state.range(0)];
auto const& pos = utils::lower_bound(first, last, item, {}, true);
benchmark::DoNotOptimize(pos);
}
}
}
BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBound4096)(benchmark::State& state) {
auto first = data.begin();
auto last = data.begin() + 4096;
std::vector<value_type> indices = prepareItems(4096);
value_type const* ip = indices.data();
size_t i = 0;
{
PerformanceCounters pc(state);
for (auto _ : state) {
auto item = ip[i++ % 4096];
auto const& pos = utils::lower_bound(first, last, item, {}, true);
benchmark::DoNotOptimize(pos);
}
}
}
BENCHMARK_REGISTER_F(BinarySearch, linearSearch)->Range(2, 1<<20);
BENCHMARK_REGISTER_F(BinarySearch, stdLowerBound)->Range(2, 1<<20);
BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBound)->Range(2, 1<<20);
BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBoundPOT)
->Arg(2)
->Arg(4)
->Arg(16)
->Arg(32)
->Arg(64)
->Arg(256)
->Arg(4096)
->Arg(32768)
->Arg(262144)
->Arg(1048576);
BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBound4096);
+20 -34
View File
@@ -79,7 +79,7 @@ public:
using const_pointer = const value_type*;
using const_iterator = const value_type*;
constexpr StaticString() noexcept = default;
constexpr StaticString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
// initialization from a string literal
template<size_t N>
@@ -149,6 +149,14 @@ public:
size_type getHash() const noexcept { return mHash; }
struct Hasher {
typedef StaticString argument_type;
typedef size_t result_type;
result_type operator()(const argument_type& s) const noexcept {
return s.getHash();
}
};
private:
const_pointer mString = nullptr;
size_type mLength = 0;
@@ -200,7 +208,7 @@ public:
using iterator = value_type*;
using const_iterator = const value_type*;
CString() noexcept = default;
CString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
// Allocates memory and appends a null. This constructor can be used to hold arbitrary data
// inside the string (i.e. it can contain nulls or non-ASCII encodings).
@@ -220,7 +228,7 @@ public:
: CString(other, N - 1) {
}
CString(StaticString const& s) : CString(s.c_str(), s.size()) {}
CString(StaticString const& s) : CString(s.c_str(), s.size()) {} // NOLINT(google-explicit-constructor)
CString(const CString& rhs);
@@ -309,11 +317,19 @@ public:
}
// placement new declared as "throw" to avoid the compiler's null-check
inline void* operator new(size_t size, void* ptr) {
inline void* operator new(size_t, void* ptr) {
assert(ptr);
return ptr;
}
struct Hasher : private hashCStrings {
typedef CString argument_type;
typedef size_t result_type;
result_type operator()(const argument_type& s) const noexcept {
return hashCStrings::operator()(s.c_str());
}
};
private:
struct Data {
size_type length;
@@ -365,34 +381,4 @@ CString to_string(T value) noexcept;
} // namespace utils
// FIXME: how could we not include this one?
// needed for std::hash, since implementation is inline, this would not cause
// binaries incompatibilities if another STL version was used.
#include <functional>
namespace std {
//! \privatesection
template<>
struct hash<utils::CString> {
typedef utils::CString argument_type;
typedef size_t result_type;
utils::hashCStrings hasher;
size_t operator()(const utils::CString& s) const noexcept {
return hasher(s.c_str());
}
};
//! \privatesection
template<>
struct hash<utils::StaticString> {
typedef utils::StaticString argument_type;
typedef size_t result_type;
size_t operator()(const utils::StaticString& s) const noexcept {
return s.getHash();
}
};
} // namespace std
#endif // TNT_UTILS_CSTRING_H
+9 -19
View File
@@ -19,9 +19,6 @@
#include <utils/compiler.h>
// FIXME: could we get rid of <functional>
#include <functional> // for std::hash
#include <stdint.h>
#include <stddef.h>
@@ -30,7 +27,7 @@ namespace utils {
class UTILS_PUBLIC Entity {
public:
// this can be used to create an array of to-be-filled entities (see create())
Entity() noexcept = default;
Entity() noexcept { } // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
// Entities can be copied
Entity(const Entity& e) noexcept = default;
@@ -68,10 +65,17 @@ public:
return Entity{ Type(identity) };
}
struct Hasher {
typedef Entity argument_type;
typedef size_t result_type;
result_type operator()(argument_type const& e) const {
return e.getId();
}
};
private:
friend class EntityManager;
friend class EntityManagerImpl;
friend struct std::hash<Entity>;
using Type = uint32_t;
explicit Entity(Type identity) noexcept : mIdentity(identity) { }
@@ -81,18 +85,4 @@ private:
} // namespace utils
namespace std {
template<>
struct hash<utils::Entity> {
typedef utils::Entity argument_type;
typedef size_t result_type;
result_type operator()(argument_type const& e) const {
return e.getId();
}
};
} // namespace std
#endif // TNT_UTILS_ENTITY_H
+2 -4
View File
@@ -22,8 +22,7 @@
#include <stdint.h>
#include <stddef.h>
namespace utils {
namespace hash {
namespace utils::hash {
// Hash function that takes an arbitrary swath of word-aligned data.
inline uint32_t murmur3(const uint32_t* key, size_t wordCount, uint32_t seed) noexcept {
@@ -99,7 +98,6 @@ inline void combine_fast(size_t& seed, const T& v) noexcept {
seed ^= hasher(v) << 1u;
}
} // namespace hash
} // namespace utils
} // namespace utils::hash
#endif // TNT_UTILS_HASH_H
@@ -17,40 +17,19 @@
#ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H
#define TNT_UTILS_NAMECOMPONENTMANAGER_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/Entity.h>
#include <utils/EntityInstance.h>
#include <utils/SingleInstanceComponentManager.h>
#include <functional>
#include <stddef.h>
#include <stdint.h>
namespace utils {
class EntityManager;
namespace details {
class SafeString {
public:
SafeString() noexcept = default;
explicit SafeString(const char* str) noexcept : mCStr(strdup(str)) { }
SafeString(SafeString&& rhs) noexcept : mCStr(rhs.mCStr) { rhs.mCStr = nullptr; }
SafeString& operator=(SafeString&& rhs) noexcept {
std::swap(mCStr, rhs.mCStr);
return *this;
}
~SafeString() { free((void*)mCStr); }
const char* c_str() const noexcept { return mCStr; }
private:
char const* mCStr = nullptr;
};
} // namespace details
/**
* \class NameComponentManager NameComponentManager.h utils/NameComponentManager.h
* \brief Allows clients to associate string labels with entities.
@@ -69,7 +48,7 @@ private:
* printf("%s\n", names->getName(names->getInstance(myEntity));
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager<details::SafeString> {
class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager<utils::CString> {
public:
using Instance = EntityInstance<NameComponentManager>;
@@ -93,7 +72,7 @@ public:
* @return Non-zero handle if the entity has a name component, 0 otherwise.
*/
Instance getInstance(Entity e) const noexcept {
return Instance(SingleInstanceComponentManager::getInstance(e));
return { SingleInstanceComponentManager::getInstance(e) };
}
/*! \cond PRIVATE */
@@ -256,7 +256,7 @@ protected:
private:
// maps an entity to an instance index
tsl::robin_map<Entity, Instance> mInstanceMap;
tsl::robin_map<Entity, Instance, Entity::Hasher> mInstanceMap;
default_random_engine mRng;
};
@@ -19,7 +19,6 @@
#include <array> // note: this is safe, see how std::array is used below (inline / private)
#include <cstddef>
#include <functional>
#include <utility>
#include <stddef.h>
-69
View File
@@ -19,7 +19,6 @@
#include <utils/compiler.h>
#include <functional> // for std::less
#include <type_traits> // for std::enable_if
#include <limits.h>
@@ -168,74 +167,6 @@ T log2i(T x) noexcept {
return (sizeof(x) * 8 - 1u) - clz(x);
}
/*
* branch-less version of std::lower_bound and std::upper_bound.
* These versions are intended to be fully inlined, which only happens when the size
* of the array is known at compile time. This code also performs better if the
* array is a power-of-two in size.
*
* These code works even if the conditions above are not met, and becomes a less-branches
* algorithm instead of a branch-less one!
*/
template<typename RandomAccessIterator, typename T, typename COMPARE = typename std::less<T>>
inline UTILS_PUBLIC
RandomAccessIterator lower_bound(
RandomAccessIterator first, RandomAccessIterator last, const T& value,
COMPARE comp = std::less<T>(),
bool assume_power_of_two = false) {
size_t len = last - first;
if (!assume_power_of_two) {
// handle non power-of-two sized arrays. If it's POT, the next line is a no-op
// and gets optimized out if the size is known at compile time.
len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2
size_t difference = (last - first) - len;
// If len was already a POT, then difference will be 0.
// We need to explicitly check this case to avoid dereferencing past the end of the array
first += !difference || comp(first[len], value) ? difference : 0;
}
while (len) {
// The number of repetitions here doesn't affect the result. We manually unroll the loop
// twice, to guarantee we have at least two iterations without branches (for the case
// where the size is not known at compile time
first += comp(first[len >>= 1u], value) ? len : 0;
first += comp(first[len >>= 1u], value) ? len : 0;
}
first += comp(*first, value);
return first;
}
template<typename RandomAccessIterator, typename T, typename COMPARE = typename std::less<T>>
inline UTILS_PUBLIC
RandomAccessIterator upper_bound(
RandomAccessIterator first, RandomAccessIterator last,
const T& value, COMPARE comp = std::less<T>(),
bool assume_power_of_two = false) {
size_t len = last - first;
if (!assume_power_of_two) {
// handle non power-of-two sized arrays. If it's POT, the next line is a no-op
// and gets optimized out if the size is known at compile time.
len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2
size_t difference = (last - first) - len;
// If len was already a POT, then difference will be 0.
// We need to explicitly check this case to avoid dereferencing past the end of the array
first += !difference || comp(value, first[len]) ? 0 : difference;
}
while (len) {
// The number of repetitions here doesn't affect the result. We manually unroll the loop
// twice, to guarantee we have at least two iterations without branches (for the case
// where the size is not known at compile time
first += !comp(value, first[len >>= 1u]) ? len : 0;
first += !comp(value, first[len >>= 1u]) ? len : 0;
}
first += !comp(value, *first);
return first;
}
template<typename RandomAccessIterator, typename COMPARE>
inline UTILS_PUBLIC
RandomAccessIterator partition_point(
+1 -1
View File
@@ -178,7 +178,7 @@ private:
tsl::robin_set<Listener*> mListeners;
#if FILAMENT_UTILS_TRACK_ENTITIES
tsl::robin_map<Entity, CallStack> mDebugActiveEntities;
tsl::robin_map<Entity, CallStack, Entity::Hasher> mDebugActiveEntities;
#endif
};
+1 -1
View File
@@ -28,7 +28,7 @@ NameComponentManager::~NameComponentManager() = default;
void NameComponentManager::setName(Instance instance, const char* name) noexcept {
if (instance) {
elementAt<NAME>(instance) = details::SafeString{ name };
elementAt<NAME>(instance) = CString{ name };
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ TEST(StaticString, hash) {
EXPECT_NE(a.getHash(), c.getHash());
EXPECT_NE(b.getHash(), c.getHash());
std::hash<StaticString> ha;
StaticString::Hasher ha;
EXPECT_EQ(ha(a), a.getHash());
}
-85
View File
@@ -138,91 +138,6 @@ TEST(AlgorithmTest, popcount) {
}
}
TEST(AlgorithmTest, UpperBounds) {
int* r;
int array[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
for (int i = 0; i < 8; i++) {
r = utils::upper_bound(std::begin(array), std::end(array), array[i]);
EXPECT_EQ(i + 1, r - std::begin(array));
}
r = utils::upper_bound(std::begin(array), std::end(array), 100);
EXPECT_EQ(std::end(array), r);
r = utils::upper_bound(std::begin(array), std::end(array), -1);
EXPECT_EQ(std::begin(array), r);
int array2[8] = { 0, 0, 0, 1, 1, 1, 2, 2 };
r = utils::upper_bound(std::begin(array2), std::end(array2), 0);
EXPECT_EQ(std::begin(array2) + 3, r);
r = utils::upper_bound(std::begin(array2), std::end(array2), 1);
EXPECT_EQ(std::begin(array2) + 6, r);
r = utils::upper_bound(std::begin(array2), std::end(array2), 2);
EXPECT_EQ(std::end(array2), r);
int arrayNPotEven[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < 10; i++) {
r = utils::upper_bound(std::begin(arrayNPotEven), std::end(arrayNPotEven), arrayNPotEven[i]);
EXPECT_EQ(i + 1, r - std::begin(arrayNPotEven));
}
int arrayNPotOdd[15] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
for (int i = 0; i < 15; i++) {
r = utils::upper_bound(std::begin(arrayNPotOdd), std::end(arrayNPotOdd), arrayNPotOdd[i]);
EXPECT_EQ(i + 1, r - std::begin(arrayNPotOdd));
}
std::array<int, 4> arr = {{1, 10, 15, 50}};
EXPECT_EQ(50, *utils::upper_bound(arr.begin(), arr.end(), 15));
}
TEST(AlgorithmTest, LowerBounds) {
int* r;
int array[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
for (int i = 0; i < 8; i++) {
r = utils::lower_bound(std::begin(array), std::end(array), array[i]);
EXPECT_EQ(i, r - std::begin(array));
}
r = utils::lower_bound(std::begin(array), std::end(array), 100);
EXPECT_EQ(std::end(array), r);
r = utils::lower_bound(std::begin(array), std::end(array), -1);
EXPECT_EQ(std::begin(array), r);
int array2[8] = { 0, 0, 0, 1, 1, 1, 2, 2 };
r = utils::lower_bound(std::begin(array2), std::end(array2), 0);
EXPECT_EQ(std::begin(array2), r);
r = utils::lower_bound(std::begin(array2), std::end(array2), 1);
EXPECT_EQ(std::begin(array2) + 3, r);
r = utils::lower_bound(std::begin(array2), std::end(array2), 2);
EXPECT_EQ(std::begin(array2) + 6, r);
int arrayNPotEven[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < 10; i++) {
r = utils::lower_bound(std::begin(arrayNPotEven), std::end(arrayNPotEven), arrayNPotEven[i]);
EXPECT_EQ(i, r - std::begin(arrayNPotEven));
}
int arrayNPotOdd[15] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
for (int i = 0; i < 15; i++) {
r = utils::lower_bound(std::begin(arrayNPotOdd), std::end(arrayNPotOdd), arrayNPotOdd[i]);
EXPECT_EQ(i, r - std::begin(arrayNPotOdd));
}
std::array<int, 4> arr = {{1, 10, 15, 50}};
EXPECT_EQ(15, *utils::lower_bound(arr.begin(), arr.end(), 15));
}
TEST(AlgorithmTest, Partition) {
int* r;
int array[8] = { 2, 5, 4, 8, 9, 9, 9, 9 };
+1
View File
@@ -36,6 +36,7 @@
#include <math/mat4.h>
#include <math/vec3.h>
#include <functional>
#include <vector>
namespace filagui {