diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3172fbffb6..5978861a69 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -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` definitions for `libutils` types. Use `T::Hasher` explicitly instead. [⚠️ **API Change**] ## v1.23.1 diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index 58f543ee8a..ab62179c60 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -26,6 +26,8 @@ #include +#include + #include // Command debugging off. debugging virtuals are not called. diff --git a/filament/backend/include/private/backend/SamplerGroup.h b/filament/backend/include/private/backend/SamplerGroup.h index f48952235f..7e4ebbd2af 100644 --- a/filament/backend/include/private/backend/SamplerGroup.h +++ b/filament/backend/include/private/backend/SamplerGroup.h @@ -17,17 +17,18 @@ #ifndef TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H #define TNT_FILAMENT_BACKEND_PRIVATE_SAMPLERGROUP_H -#include -#include - #include #include #include #include -namespace filament { -namespace backend { +#include +#include + +#include + +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 diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index be31ee191e..e0705178e1 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -316,7 +316,12 @@ private: mutable bool mHasMaterial{}; }; - tsl::robin_map 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; diff --git a/filament/src/details/DebugRegistry.h b/filament/src/details/DebugRegistry.h index 017e6e4fb5..5207629511 100644 --- a/filament/src/details/DebugRegistry.h +++ b/filament/src/details/DebugRegistry.h @@ -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 mPropertyMap; - std::unordered_map mDataSourceMap; + std::unordered_map mPropertyMap; + std::unordered_map mDataSourceMap; }; FILAMENT_UPCAST(DebugRegistry) diff --git a/filament/src/details/Scene.h b/filament/src/details/Scene.h index bd79755b2a..b578d32fcb 100644 --- a/filament/src/details/Scene.h +++ b/filament/src/details/Scene.h @@ -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 mEntities; + tsl::robin_set mEntities; /* diff --git a/filament/src/fg/Blackboard.h b/filament/src/fg/Blackboard.h index 0912c0f893..808ba08c40 100644 --- a/filament/src/fg/Blackboard.h +++ b/filament/src/fg/Blackboard.h @@ -26,7 +26,10 @@ namespace filament { class Blackboard { - using Container = std::unordered_map; + using Container = std::unordered_map< + utils::StaticString, + FrameGraphHandle, + utils::StaticString::Hasher>; public: Blackboard() noexcept; diff --git a/libs/filameshio/include/filameshio/MeshReader.h b/libs/filameshio/include/filameshio/MeshReader.h index f9da44bdec..2253379120 100644 --- a/libs/filameshio/include/filameshio/MeshReader.h +++ b/libs/filameshio/include/filameshio/MeshReader.h @@ -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; diff --git a/libs/gltfio/src/DependencyGraph.h b/libs/gltfio/src/DependencyGraph.h index 9b2928f607..8320b9ee4e 100644 --- a/libs/gltfio/src/DependencyGraph.h +++ b/libs/gltfio/src/DependencyGraph.h @@ -118,8 +118,8 @@ private: TextureNode* getStatus(filament::Texture* texture); // The following maps contain the directed edges in the graph. - tsl::robin_map mEntityToMaterial; - tsl::robin_map> mMaterialToEntity; + tsl::robin_map mEntityToMaterial; + tsl::robin_map> mMaterialToEntity; tsl::robin_map mMaterialToTexture; tsl::robin_map> mTextureToMaterial; diff --git a/libs/gltfio/src/FFilamentInstance.h b/libs/gltfio/src/FFilamentInstance.h index 52cfdd77fa..8423147e1c 100644 --- a/libs/gltfio/src/FFilamentInstance.h +++ b/libs/gltfio/src/FFilamentInstance.h @@ -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 targets; + tsl::robin_set targets; }; struct VariantMapping { diff --git a/libs/image/src/ImageSampler.cpp b/libs/image/src/ImageSampler.cpp index 98073c4894..d922e505bc 100644 --- a/libs/image/src/ImageSampler.cpp +++ b/libs/image/src/ImageSampler.cpp @@ -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 map = { + static const unordered_map map = { { "BOX", Filter::BOX}, { "NEAREST", Filter::NEAREST}, { "HERMITE", Filter::HERMITE}, diff --git a/libs/utils/benchmark/benchmark_binary_search.cpp b/libs/utils/benchmark/benchmark_binary_search.cpp index 110a9c4088..376d59ed1d 100644 --- a/libs/utils/benchmark/benchmark_binary_search.cpp +++ b/libs/utils/benchmark/benchmark_binary_search.cpp @@ -16,14 +16,12 @@ #include "PerformanceCounters.h" -#include #include #include #include #include -#include 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 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 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 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); diff --git a/libs/utils/include/utils/CString.h b/libs/utils/include/utils/CString.h index da809d11cf..09f3d2ca6a 100644 --- a/libs/utils/include/utils/CString.h +++ b/libs/utils/include/utils/CString.h @@ -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 @@ -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 - -namespace std { - -//! \privatesection -template<> -struct hash { - 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 { - 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 diff --git a/libs/utils/include/utils/Entity.h b/libs/utils/include/utils/Entity.h index 74f417aaaa..58fdf606ae 100644 --- a/libs/utils/include/utils/Entity.h +++ b/libs/utils/include/utils/Entity.h @@ -19,9 +19,6 @@ #include -// FIXME: could we get rid of -#include // for std::hash - #include #include @@ -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; using Type = uint32_t; explicit Entity(Type identity) noexcept : mIdentity(identity) { } @@ -81,18 +85,4 @@ private: } // namespace utils - -namespace std { - -template<> -struct hash { - 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 diff --git a/libs/utils/include/utils/Hash.h b/libs/utils/include/utils/Hash.h index 8d0bd9ff16..f17dfc8655 100644 --- a/libs/utils/include/utils/Hash.h +++ b/libs/utils/include/utils/Hash.h @@ -22,8 +22,7 @@ #include #include -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 diff --git a/libs/utils/include/utils/NameComponentManager.h b/libs/utils/include/utils/NameComponentManager.h index 62201d113a..9e31e4618d 100644 --- a/libs/utils/include/utils/NameComponentManager.h +++ b/libs/utils/include/utils/NameComponentManager.h @@ -17,40 +17,19 @@ #ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H #define TNT_UTILS_NAMECOMPONENTMANAGER_H -#include -#include -#include - #include +#include #include #include #include -#include +#include +#include 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 { +class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager { public: using Instance = EntityInstance; @@ -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 */ diff --git a/libs/utils/include/utils/SingleInstanceComponentManager.h b/libs/utils/include/utils/SingleInstanceComponentManager.h index 574d14a745..e728d6ee90 100644 --- a/libs/utils/include/utils/SingleInstanceComponentManager.h +++ b/libs/utils/include/utils/SingleInstanceComponentManager.h @@ -256,7 +256,7 @@ protected: private: // maps an entity to an instance index - tsl::robin_map mInstanceMap; + tsl::robin_map mInstanceMap; default_random_engine mRng; }; diff --git a/libs/utils/include/utils/StructureOfArrays.h b/libs/utils/include/utils/StructureOfArrays.h index dd879a6fa3..41cd8b890c 100644 --- a/libs/utils/include/utils/StructureOfArrays.h +++ b/libs/utils/include/utils/StructureOfArrays.h @@ -19,7 +19,6 @@ #include // note: this is safe, see how std::array is used below (inline / private) #include -#include #include #include diff --git a/libs/utils/include/utils/algorithm.h b/libs/utils/include/utils/algorithm.h index 72240c2730..6d12ffc63a 100644 --- a/libs/utils/include/utils/algorithm.h +++ b/libs/utils/include/utils/algorithm.h @@ -19,7 +19,6 @@ #include -#include // for std::less #include // for std::enable_if #include @@ -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> -inline UTILS_PUBLIC -RandomAccessIterator lower_bound( - RandomAccessIterator first, RandomAccessIterator last, const T& value, - COMPARE comp = std::less(), - 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> -inline UTILS_PUBLIC -RandomAccessIterator upper_bound( - RandomAccessIterator first, RandomAccessIterator last, - const T& value, COMPARE comp = std::less(), - 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 inline UTILS_PUBLIC RandomAccessIterator partition_point( diff --git a/libs/utils/src/EntityManagerImpl.h b/libs/utils/src/EntityManagerImpl.h index f8ea374b50..e9c7ef1699 100644 --- a/libs/utils/src/EntityManagerImpl.h +++ b/libs/utils/src/EntityManagerImpl.h @@ -178,7 +178,7 @@ private: tsl::robin_set mListeners; #if FILAMENT_UTILS_TRACK_ENTITIES - tsl::robin_map mDebugActiveEntities; + tsl::robin_map mDebugActiveEntities; #endif }; diff --git a/libs/utils/src/NameComponentManager.cpp b/libs/utils/src/NameComponentManager.cpp index b3fd2daedc..98bb3839a3 100644 --- a/libs/utils/src/NameComponentManager.cpp +++ b/libs/utils/src/NameComponentManager.cpp @@ -28,7 +28,7 @@ NameComponentManager::~NameComponentManager() = default; void NameComponentManager::setName(Instance instance, const char* name) noexcept { if (instance) { - elementAt(instance) = details::SafeString{ name }; + elementAt(instance) = CString{ name }; } } diff --git a/libs/utils/test/test_CString.cpp b/libs/utils/test/test_CString.cpp index 7333e69e1c..16ef2c2baa 100644 --- a/libs/utils/test/test_CString.cpp +++ b/libs/utils/test/test_CString.cpp @@ -36,7 +36,7 @@ TEST(StaticString, hash) { EXPECT_NE(a.getHash(), c.getHash()); EXPECT_NE(b.getHash(), c.getHash()); - std::hash ha; + StaticString::Hasher ha; EXPECT_EQ(ha(a), a.getHash()); } diff --git a/libs/utils/test/test_algorithm.cpp b/libs/utils/test/test_algorithm.cpp index 97f4401ad8..fa36aff0dc 100644 --- a/libs/utils/test/test_algorithm.cpp +++ b/libs/utils/test/test_algorithm.cpp @@ -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 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 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 }; diff --git a/libs/viewer/include/viewer/ViewerGui.h b/libs/viewer/include/viewer/ViewerGui.h index 348b0870ab..8192c32ee7 100644 --- a/libs/viewer/include/viewer/ViewerGui.h +++ b/libs/viewer/include/viewer/ViewerGui.h @@ -36,6 +36,7 @@ #include #include +#include #include namespace filagui {