// // immer: immutable data structures for C++ // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente // // This software is distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt // #pragma once #include #include #include #include #include #include #if defined(_MSC_VER) #include // for __lzcnt* #endif namespace immer { namespace detail { template using aligned_storage_for = typename std::aligned_storage::type; template T& auto_const_cast(const T& x) { return const_cast(x); } template T&& auto_const_cast(const T&& x) { return const_cast(std::move(x)); } template auto uninitialized_move(Iter1 in1, Iter1 in2, Iter2 out) { return std::uninitialized_copy( std::make_move_iterator(in1), std::make_move_iterator(in2), out); } template void destroy(T* first, T* last) { for (; first != last; ++first) first->~T(); } template void destroy_n(T* p, Size n) { auto e = p + n; for (; p != e; ++p) p->~T(); } template T* make(Args&&... args) { auto ptr = Heap::allocate(sizeof(T)); try { return new (ptr) T{std::forward(args)...}; } catch (...) { Heap::deallocate(sizeof(T), ptr); throw; } } struct not_supported_t {}; struct empty_t {}; template struct exact_t { T value; exact_t(T v) : value{v} {}; }; template inline constexpr auto clz_(T) -> not_supported_t { IMMER_UNREACHABLE; return {}; } #if defined(_MSC_VER) // inline auto clz_(unsigned short x) { return __lzcnt16(x); } // inline auto clz_(unsigned int x) { return __lzcnt(x); } // inline auto clz_(unsigned __int64 x) { return __lzcnt64(x); } #else inline constexpr auto clz_(unsigned int x) { return __builtin_clz(x); } inline constexpr auto clz_(unsigned long x) { return __builtin_clzl(x); } inline constexpr auto clz_(unsigned long long x) { return __builtin_clzll(x); } #endif template inline constexpr T log2_aux(T x, T r = 0) { return x <= 1 ? r : log2_aux(x >> 1, r + 1); } template inline constexpr auto log2(T x) -> std:: enable_if_t::value, T> { return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - clz_(x); } template inline constexpr auto log2(T x) -> std::enable_if_t::value, T> { return log2_aux(x); } template auto static_if(F&& f) -> std::enable_if_t { std::forward(f)(empty_t{}); } template auto static_if(F&& f) -> std::enable_if_t {} template auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t { return std::forward(f1)(empty_t{}); } template auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t { return std::forward(f2)(empty_t{}); } template struct constantly { template T operator()(Args&&...) const { return value; } }; /*! * An alias to `std::distance` */ template , bool> = true> typename std::iterator_traits::difference_type distance(Iterator first, Sentinel last) { return std::distance(first, last); } /*! * Equivalent of the `std::distance` applied to the sentinel-delimited * forward range @f$ [first, last) @f$ */ template ) &&detail:: is_forward_iterator_v && detail::compatible_sentinel_v && (!detail::is_subtractable_v), bool> = true> typename std::iterator_traits::difference_type distance(Iterator first, Sentinel last) { std::size_t result = 0; while (first != last) { ++first; ++result; } return result; } /*! * Equivalent of the `std::distance` applied to the sentinel-delimited * random access range @f$ [first, last) @f$ */ template ) &&detail:: is_forward_iterator_v && detail::compatible_sentinel_v && detail::is_subtractable_v, bool> = true> typename std::iterator_traits::difference_type distance(Iterator first, Sentinel last) { return last - first; } /*! * An alias to `std::uninitialized_copy` */ template < typename Iterator, typename Sentinel, typename SinkIter, std::enable_if_t< detail::std_uninitialized_copy_supports_v, bool> = true> SinkIter uninitialized_copy(Iterator first, Sentinel last, SinkIter d_first) { return std::uninitialized_copy(first, last, d_first); } /*! * Equivalent of the `std::uninitialized_copy` applied to the * sentinel-delimited forward range @f$ [first, last) @f$ */ template ) &&detail:: compatible_sentinel_v && detail::is_forward_iterator_v, bool> = true> SinkIter uninitialized_copy(SourceIter first, Sent last, SinkIter d_first) { auto current = d_first; try { while (first != last) { *current++ = *first; ++first; } } catch (...) { using Value = typename std::iterator_traits::value_type; for (; d_first != current; ++d_first) { d_first->~Value(); } throw; } return current; } } // namespace detail } // namespace immer