You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

288 lines
7.3 KiB

#pragma once
#include <memory>
#include "function_traits.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace vlc
{
#if (defined(_MSC_VER) && _MSC_VER <= 1800) || (!defined(_MSC_VER) && __cplusplus <= 201103L)
template<typename T, typename ...Args> std::unique_ptr<T> make_unique(Args&& ...args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#else
using std::make_unique;
#endif
template <size_t... Ints>
struct index_sequence
{
using type = index_sequence;
using value_type = size_t;
static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
};
// --------------------------------------------------------------
template <class Sequence1, class Sequence2>
struct _merge_and_renumber;
template <size_t... I1, size_t... I2>
struct _merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
: index_sequence<I1..., (sizeof...(I1)+I2)...>
{ };
// --------------------------------------------------------------
template <size_t N>
struct make_index_sequence
: _merge_and_renumber<typename make_index_sequence<N / 2>::type,
typename make_index_sequence<N - N / 2>::type>
{ };
template<> struct make_index_sequence<0> : index_sequence<> { };
template<> struct make_index_sequence<1> : index_sequence<0> { };
namespace detail
{
template<typename T>
struct target_type
{
typedef void type;
};
template<typename Class, typename Member>
struct target_type<Member Class::*>
{
typedef Class type;
};
//Is reference to pointer target or derived
template<typename Object, typename Pointer>
struct is_target_reference :
public std::integral_constant<
bool,
std::is_reference<Object>::value &&
std::is_base_of<
typename target_type<Pointer>::type,
typename std::decay<Object>::type
>::value
>
{};
}
// Minimal invoke implementation from https://github.com/tomaszkam/proposals/blob/master/implementation/invoke/invoke_cpp11.hpp
template<typename Functor, typename Object, typename... Args>
constexpr auto invoke(Functor&& functor, Object&& object, Args&&... args)
-> typename std::enable_if<
std::is_member_function_pointer<
typename std::decay<Functor>::type
>::value &&
detail::is_target_reference<
Object&&,
typename std::decay<Functor>::type
>::value,
decltype((std::forward<Object>(object).*functor)(std::forward<Args>(args)...))
>::type
{
return (std::forward<Object>(object).*functor)(std::forward<Args>(args)...);
}
template<typename Functor, typename Object, typename... Args>
constexpr auto invoke(Functor&& functor, Object&& object, Args&&... args)
-> typename std::enable_if<
std::is_member_function_pointer<
typename std::decay<Functor>::type
>::value &&
!detail::is_target_reference<
Object&&,
typename std::decay<Functor>::type
>::value,
decltype(((*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
>::type
{
return ((*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}
template<typename Functor, typename Object>
constexpr auto invoke(Functor&& functor, Object&& object)
-> typename std::enable_if<
std::is_member_object_pointer<
typename std::decay<Functor>::type
>::value &&
detail::is_target_reference<
Object&&,
typename std::decay<Functor>::type
>::value,
decltype((std::forward<Object>(object).*functor))
>::type
{
return std::forward<Object>(object).*functor;
}
template<typename Functor, typename Object>
constexpr auto invoke(Functor&& functor, Object&& object)
-> typename std::enable_if <
std::is_member_object_pointer<
typename std::decay<Functor>::type
>::value &&
!detail::is_target_reference<
Object&&,
typename std::decay<Functor>::type
>::value,
decltype((*std::forward<Object>(object)).*functor)
> ::type
{
return (*std::forward<Object>(object)).*functor;
}
template<typename Functor, typename... Args>
constexpr auto invoke(Functor&& functor, Args&&... args)
-> typename std::enable_if<
!std::is_member_pointer<
typename std::decay<Functor>::type
>::value,
decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
>::type
{
return std::forward<Functor>(functor)(std::forward<Args>(args)...);
}
namespace detail
{
template<typename Fn, typename ArgsTuple, std::size_t... I> constexpr auto apply_impl(Fn&& f, ArgsTuple&& tpl, index_sequence<I...>)
-> decltype(vlc::invoke(std::forward<Fn>(f), std::get<I>(std::forward<ArgsTuple>(tpl))...))
{
return vlc::invoke(std::forward<Fn>(f), std::get<I>(std::forward<ArgsTuple>(tpl))...);
}
}
template<typename Fn, typename ArgsTuple> constexpr auto apply(Fn&& f, ArgsTuple&& tpl)
-> decltype(
detail::apply_impl(std::forward<Fn>(f),
std::forward<ArgsTuple>(tpl),
make_index_sequence<std::tuple_size<typename std::decay<ArgsTuple>::type>::value> {})
)
{
return detail::apply_impl(std::forward<Fn>(f), std::forward<ArgsTuple>(tpl), make_index_sequence<std::tuple_size<typename std::decay<ArgsTuple>::type>::value> {});
}
template<class C> constexpr auto data(C& c) -> decltype(c.data())
{
return c.data();
}
template<class C> constexpr auto data(const C& c) -> decltype(c.data())
{
return c.data();
}
template<class T, std::size_t N> constexpr T* data(T (&array)[N]) noexcept
{
return array;
}
template<class E> constexpr const E* data(std::initializer_list<E> il) noexcept
{
return il.begin();
}
constexpr void data(...);
template<class C> constexpr auto size(const C& c) -> decltype(c.size())
{
return c.size();
}
template <class T, std::size_t N> constexpr std::size_t size(const T(&array)[N]) noexcept
{
return N;
}
template <class T, std::ptrdiff_t N> constexpr std::ptrdiff_t ssize(const T(&array)[N]) noexcept
{
return N;
}
inline size_t align_up(size_t size, size_t alignment)
{
assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
return (size + alignment - 1) & ~(alignment - 1);
}
inline void* align_ptr(void* ptr, size_t alignment)
{
assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
return reinterpret_cast<void*>(align_up(reinterpret_cast<uintptr_t>(ptr), alignment));
}
inline bool is_aligned(const void* ptr, size_t alignment)
{
assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
return (uintptr_t(ptr) & (alignment - 1)) == 0;
}
inline uint32_t ctz(uint64_t x)
{
#ifdef _MSC_VER
unsigned long trailing_zero = 0;
#ifdef _WIN64
if (!_BitScanForward64(&trailing_zero, x))
{
return 64;
}
#else
if (!_BitScanForward(&trailing_zero, (uint32_t)x))
{
if (!_BitScanForward(&trailing_zero, (uint32_t)(x >> 32)))
{
return 64;
}
trailing_zero += 32;
}
#endif
return trailing_zero;
#else
return x != 0ull ? (uint32_t)__builtin_ctzll(x) : 64;
#endif
}
inline uint32_t clz(uint64_t x)
{
#ifdef _MSC_VER
unsigned long leading_zero = 0;
#ifdef _WIN64
if (!_BitScanReverse64(&leading_zero, x))
{
return 64;
}
return 63 - leading_zero;
#else
if (!_BitScanReverse(&leading_zero, (uint32_t)(x >> 32)))
{
if (!_BitScanReverse(&leading_zero, (uint32_t)x))
{
return 64;
}
return 32 + 31 - leading_zero;
}
return 31 - leading_zero;
#endif
#else
return x != 0ull ? (uint32_t)__builtin_clzll(x) : 64;
#endif
}
}