|
|
- #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
- }
- }
|