Browse Source

utility: overloaded and y_combinator

Michele Caini 6 years ago
parent
commit
a95aa81850
2 changed files with 80 additions and 0 deletions
  1. 54 0
      src/entt/core/utility.hpp
  2. 26 0
      test/entt/core/utility.cpp

+ 54 - 0
src/entt/core/utility.hpp

@@ -44,6 +44,60 @@ template<typename Type>
 constexpr auto overload(Type *func) ENTT_NOEXCEPT { return func; }
 
 
+/**
+ * @brief Helper type for visitors.
+ * @tparam Func Types of function objects.
+ */
+template<class... Func>
+struct overloaded: Func... {
+    using Func::operator()...;
+};
+
+
+/**
+ * @brief Deduction guide.
+ * @tparam Func Types of function objects.
+ */
+template<class... Type>
+overloaded(Type...) -> overloaded<Type...>;
+
+
+/**
+ * @brief Basic implementation of a y-combinator.
+ * @tparam Func Type of a potentially recursive function.
+ */
+template<class Func>
+struct y_combinator {
+    /**
+     * @brief Constructs a y-combinator from a given function.
+     * @param recursive A potentially recursive function.
+     */
+    y_combinator(Func recursive):
+        func{std::move(recursive)}
+    {}
+
+    /**
+     * @brief Invokes a y-combinator and therefore its underlying function.
+     * @tparam Args Types of arguments to use to invoke the underlying function.
+     * @param args Parameters to use to invoke the underlying function.
+     * @return Return value of the underlying function, if any.
+     */
+    template <class... Args>
+    decltype(auto) operator()(Args &&... args) const {
+        return func(*this, std::forward<Args>(args)...);
+    }
+
+    /*! @copydoc operator()() */
+    template <class... Args>
+    decltype(auto) operator()(Args &&... args) {
+        return func(*this, std::forward<Args>(args)...);
+    }
+
+private:
+    Func func;
+};
+
+
 }
 
 

+ 26 - 0
test/entt/core/utility.cpp

@@ -1,3 +1,4 @@
+#include <utility>
 #include <gtest/gtest.h>
 #include <entt/core/utility.hpp>
 
@@ -32,3 +33,28 @@ TEST(Utility, Overload) {
     ASSERT_NO_THROW((instance.*entt::overload<void(int)>(&Functions::bar))(0));
     ASSERT_NO_THROW((instance.*entt::overload<void()>(&Functions::bar))());
 }
+
+TEST(Utility, Overloaded) {
+    int iv = 0;
+    char cv = '\0';
+
+    entt::overloaded func{
+        [&iv](int value) { iv = value; },
+        [&cv](char value) { cv = value; }
+    };
+
+    func(42);
+    func('c');
+
+    ASSERT_EQ(iv, 42);
+    ASSERT_EQ(cv, 'c');
+}
+
+TEST(Utility, YCombinator) {
+    entt::y_combinator gauss([](auto &&self, unsigned int value) -> unsigned int {
+        return value ? (value + self(value-1u)) : 0;
+    });
+
+    ASSERT_EQ(gauss(3u), 3u*4u/2u);
+    ASSERT_EQ(std::as_const(gauss)(7u), 7u*8u/2u);
+}