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

1 year ago
  1. #pragma once
  2. #include <memory>
  3. #include "function_traits.h"
  4. #ifdef _MSC_VER
  5. #include <intrin.h>
  6. #endif
  7. namespace vlc
  8. {
  9. #if (defined(_MSC_VER) && _MSC_VER <= 1800) || (!defined(_MSC_VER) && __cplusplus <= 201103L)
  10. template<typename T, typename ...Args> std::unique_ptr<T> make_unique(Args&& ...args)
  11. {
  12. return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
  13. }
  14. #else
  15. using std::make_unique;
  16. #endif
  17. template <size_t... Ints>
  18. struct index_sequence
  19. {
  20. using type = index_sequence;
  21. using value_type = size_t;
  22. static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
  23. };
  24. // --------------------------------------------------------------
  25. template <class Sequence1, class Sequence2>
  26. struct _merge_and_renumber;
  27. template <size_t... I1, size_t... I2>
  28. struct _merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
  29. : index_sequence<I1..., (sizeof...(I1)+I2)...>
  30. { };
  31. // --------------------------------------------------------------
  32. template <size_t N>
  33. struct make_index_sequence
  34. : _merge_and_renumber<typename make_index_sequence<N / 2>::type,
  35. typename make_index_sequence<N - N / 2>::type>
  36. { };
  37. template<> struct make_index_sequence<0> : index_sequence<> { };
  38. template<> struct make_index_sequence<1> : index_sequence<0> { };
  39. namespace detail
  40. {
  41. template<typename T>
  42. struct target_type
  43. {
  44. typedef void type;
  45. };
  46. template<typename Class, typename Member>
  47. struct target_type<Member Class::*>
  48. {
  49. typedef Class type;
  50. };
  51. //Is reference to pointer target or derived
  52. template<typename Object, typename Pointer>
  53. struct is_target_reference :
  54. public std::integral_constant<
  55. bool,
  56. std::is_reference<Object>::value &&
  57. std::is_base_of<
  58. typename target_type<Pointer>::type,
  59. typename std::decay<Object>::type
  60. >::value
  61. >
  62. {};
  63. }
  64. // Minimal invoke implementation from https://github.com/tomaszkam/proposals/blob/master/implementation/invoke/invoke_cpp11.hpp
  65. template<typename Functor, typename Object, typename... Args>
  66. constexpr auto invoke(Functor&& functor, Object&& object, Args&&... args)
  67. -> typename std::enable_if<
  68. std::is_member_function_pointer<
  69. typename std::decay<Functor>::type
  70. >::value &&
  71. detail::is_target_reference<
  72. Object&&,
  73. typename std::decay<Functor>::type
  74. >::value,
  75. decltype((std::forward<Object>(object).*functor)(std::forward<Args>(args)...))
  76. >::type
  77. {
  78. return (std::forward<Object>(object).*functor)(std::forward<Args>(args)...);
  79. }
  80. template<typename Functor, typename Object, typename... Args>
  81. constexpr auto invoke(Functor&& functor, Object&& object, Args&&... args)
  82. -> typename std::enable_if<
  83. std::is_member_function_pointer<
  84. typename std::decay<Functor>::type
  85. >::value &&
  86. !detail::is_target_reference<
  87. Object&&,
  88. typename std::decay<Functor>::type
  89. >::value,
  90. decltype(((*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
  91. >::type
  92. {
  93. return ((*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
  94. }
  95. template<typename Functor, typename Object>
  96. constexpr auto invoke(Functor&& functor, Object&& object)
  97. -> typename std::enable_if<
  98. std::is_member_object_pointer<
  99. typename std::decay<Functor>::type
  100. >::value &&
  101. detail::is_target_reference<
  102. Object&&,
  103. typename std::decay<Functor>::type
  104. >::value,
  105. decltype((std::forward<Object>(object).*functor))
  106. >::type
  107. {
  108. return std::forward<Object>(object).*functor;
  109. }
  110. template<typename Functor, typename Object>
  111. constexpr auto invoke(Functor&& functor, Object&& object)
  112. -> typename std::enable_if <
  113. std::is_member_object_pointer<
  114. typename std::decay<Functor>::type
  115. >::value &&
  116. !detail::is_target_reference<
  117. Object&&,
  118. typename std::decay<Functor>::type
  119. >::value,
  120. decltype((*std::forward<Object>(object)).*functor)
  121. > ::type
  122. {
  123. return (*std::forward<Object>(object)).*functor;
  124. }
  125. template<typename Functor, typename... Args>
  126. constexpr auto invoke(Functor&& functor, Args&&... args)
  127. -> typename std::enable_if<
  128. !std::is_member_pointer<
  129. typename std::decay<Functor>::type
  130. >::value,
  131. decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
  132. >::type
  133. {
  134. return std::forward<Functor>(functor)(std::forward<Args>(args)...);
  135. }
  136. namespace detail
  137. {
  138. template<typename Fn, typename ArgsTuple, std::size_t... I> constexpr auto apply_impl(Fn&& f, ArgsTuple&& tpl, index_sequence<I...>)
  139. -> decltype(vlc::invoke(std::forward<Fn>(f), std::get<I>(std::forward<ArgsTuple>(tpl))...))
  140. {
  141. return vlc::invoke(std::forward<Fn>(f), std::get<I>(std::forward<ArgsTuple>(tpl))...);
  142. }
  143. }
  144. template<typename Fn, typename ArgsTuple> constexpr auto apply(Fn&& f, ArgsTuple&& tpl)
  145. -> decltype(
  146. detail::apply_impl(std::forward<Fn>(f),
  147. std::forward<ArgsTuple>(tpl),
  148. make_index_sequence<std::tuple_size<typename std::decay<ArgsTuple>::type>::value> {})
  149. )
  150. {
  151. return detail::apply_impl(std::forward<Fn>(f), std::forward<ArgsTuple>(tpl), make_index_sequence<std::tuple_size<typename std::decay<ArgsTuple>::type>::value> {});
  152. }
  153. template<class C> constexpr auto data(C& c) -> decltype(c.data())
  154. {
  155. return c.data();
  156. }
  157. template<class C> constexpr auto data(const C& c) -> decltype(c.data())
  158. {
  159. return c.data();
  160. }
  161. template<class T, std::size_t N> constexpr T* data(T (&array)[N]) noexcept
  162. {
  163. return array;
  164. }
  165. template<class E> constexpr const E* data(std::initializer_list<E> il) noexcept
  166. {
  167. return il.begin();
  168. }
  169. constexpr void data(...);
  170. template<class C> constexpr auto size(const C& c) -> decltype(c.size())
  171. {
  172. return c.size();
  173. }
  174. template <class T, std::size_t N> constexpr std::size_t size(const T(&array)[N]) noexcept
  175. {
  176. return N;
  177. }
  178. template <class T, std::ptrdiff_t N> constexpr std::ptrdiff_t ssize(const T(&array)[N]) noexcept
  179. {
  180. return N;
  181. }
  182. inline size_t align_up(size_t size, size_t alignment)
  183. {
  184. assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
  185. return (size + alignment - 1) & ~(alignment - 1);
  186. }
  187. inline void* align_ptr(void* ptr, size_t alignment)
  188. {
  189. assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
  190. return reinterpret_cast<void*>(align_up(reinterpret_cast<uintptr_t>(ptr), alignment));
  191. }
  192. inline bool is_aligned(const void* ptr, size_t alignment)
  193. {
  194. assert((alignment & ~(alignment - 1)) == alignment); // Alignment should be power of two
  195. return (uintptr_t(ptr) & (alignment - 1)) == 0;
  196. }
  197. inline uint32_t ctz(uint64_t x)
  198. {
  199. #ifdef _MSC_VER
  200. unsigned long trailing_zero = 0;
  201. #ifdef _WIN64
  202. if (!_BitScanForward64(&trailing_zero, x))
  203. {
  204. return 64;
  205. }
  206. #else
  207. if (!_BitScanForward(&trailing_zero, (uint32_t)x))
  208. {
  209. if (!_BitScanForward(&trailing_zero, (uint32_t)(x >> 32)))
  210. {
  211. return 64;
  212. }
  213. trailing_zero += 32;
  214. }
  215. #endif
  216. return trailing_zero;
  217. #else
  218. return x != 0ull ? (uint32_t)__builtin_ctzll(x) : 64;
  219. #endif
  220. }
  221. inline uint32_t clz(uint64_t x)
  222. {
  223. #ifdef _MSC_VER
  224. unsigned long leading_zero = 0;
  225. #ifdef _WIN64
  226. if (!_BitScanReverse64(&leading_zero, x))
  227. {
  228. return 64;
  229. }
  230. return 63 - leading_zero;
  231. #else
  232. if (!_BitScanReverse(&leading_zero, (uint32_t)(x >> 32)))
  233. {
  234. if (!_BitScanReverse(&leading_zero, (uint32_t)x))
  235. {
  236. return 64;
  237. }
  238. return 32 + 31 - leading_zero;
  239. }
  240. return 31 - leading_zero;
  241. #endif
  242. #else
  243. return x != 0ull ? (uint32_t)__builtin_clzll(x) : 64;
  244. #endif
  245. }
  246. }