#include <cstdlib>
#include <cstring>
+#include <array>
#include <exception>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
+#include <type_traits>
#include <utility>
#include <vector>
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_;
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());
}
};
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 {};
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 {
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
}
}
} 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;
}
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; }