Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix compilation
[simgrid.git] / include / xbt / functional.hpp
index 1b3b6ea..0a07a96 100644 (file)
 #include <cstdlib>
 #include <cstring>
 
+#include <array>
 #include <exception>
 #include <functional>
 #include <memory>
 #include <string>
 #include <tuple>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -35,7 +37,7 @@ public:
     code_(std::move(code)),
     args_(std::make_shared<const std::vector<std::string>>(std::move(args)))
   {}
-  int operator()() const
+  void operator()() const
   {
     const int argc = args_->size();
     std::vector<std::string> args = *args_;
@@ -43,7 +45,7 @@ public:
     for (int i = 0; i != argc; ++i)
       argv[i] = args[i].empty() ? const_cast<char*>(""): &args[i].front();
     argv[argc] = nullptr;
-    return code_(argc, argv.get());
+    code_(argc, argv.get());
   }
 };
 
@@ -99,17 +101,16 @@ template<class T> class Task;
 
 namespace bits {
 
-  // Something similar exist in C++14:
-  template<class T>
-  constexpr T max(T a, T b)
-  {
-    return (a > b) ? a : b;
-  }
-  template<class T, class... Args>
-  constexpr T max(T a, Args... b)
-  {
-    return max(std::forward<T>(a), max(std::forward<Args>(b)...));
-  }
+  // Compute the maximum size taken by any of the given types:
+  template <class... T> struct max_size;
+  template <>
+  struct max_size<> : public std::integral_constant<std::size_t, 0> {};
+  template <class T>
+  struct max_size<T> : public std::integral_constant<std::size_t, sizeof(T)> {};
+  template <class T, class... U>
+  struct max_size<T, U...> : public std::integral_constant<std::size_t,
+    (sizeof(T) > max_size<U...>::value) ? sizeof(T) : max_size<U...>::value
+  > {};
 
   struct whatever {};
 
@@ -125,11 +126,12 @@ namespace bits {
     void (whatever::* callback)();
     whatever* data;
   };
-  typedef char any_callback[max(
-    sizeof(ptr_callback),
-    sizeof(funcptr_callback),
-    sizeof(member_funcptr_callback)
-    )];
+  constexpr std::size_t any_size = max_size<
+    ptr_callback,
+    funcptr_callback,
+    member_funcptr_callback
+  >::value;
+  typedef std::array<char, any_size> any_callback;
 
   // Union of what we can store in a Task:
   union TaskErasure {
@@ -143,10 +145,16 @@ namespace bits {
   template<class F>
   constexpr bool isUsableDirectlyInTask()
   {
+    // TODO, detect availability std::is_trivially_copyable / workaround
+#if 1
+    // std::is_trivially_copyable is not available before GCC 5.
+    return false;
+#else
     // The only types we can portably store directly in the Task are the
     // trivially copyable ones (we can memcpy) which are small enough to fit:
     return std::is_trivially_copyable<F>::value &&
       sizeof(F) <= sizeof(bits::any_callback);
+#endif
   }
 
 }
@@ -217,14 +225,14 @@ public:
         } code;
         if (!std::is_empty<F>::value)
           // AFAIU, this is safe as per [basic.types]:
-          std::memcpy(&code.code, &erasure.any, sizeof(code.code));
+          std::memcpy(&code.code, erasure.any.data(), sizeof(code.code));
         code.code(std::forward<Args>(args)...);
       },
       // Destroy:
       nullptr
     };
     if (!std::is_empty<F>::value)
-      std::memcpy(&code_.any, &code, sizeof(code));
+      std::memcpy(code_.any.data(), &code, sizeof(code));
     vtable_ = &vtable;
   }
 
@@ -265,6 +273,11 @@ public:
     vtable_ = &vtable;
   }
 
+  // TODO, Task(funcptr)
+  // TODO, Task(funcptr, data)
+  // TODO, Task(method, object)
+  // TODO, Task(stateless lambda)
+
   operator bool() const { return vtable_ != nullptr; }
   bool operator!() const { return vtable_ == nullptr; }