/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // //===-------------------------- algorithm ---------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef RANGES_V3_UTILITY_MEMORY_HPP #define RANGES_V3_UTILITY_MEMORY_HPP #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { template std::pair get_temporary_buffer_impl( std::size_t count) noexcept { RANGES_EXPECT(count >= 0); std::size_t n = static_cast(count); if(n > PTRDIFF_MAX / sizeof(T)) n = PTRDIFF_MAX / sizeof(T); void * ptr = nullptr; for(; ptr == nullptr && n > 0; n /= 2) { #if RANGES_CXX_ALIGNED_NEW < RANGES_CXX_ALIGNED_NEW_17 static_assert(alignof(T) <= alignof(std::max_align_t), "Sorry: over-aligned types are supported only with C++17."); #else // RANGES_CXX_ALIGNED_NEW if(RANGES_CONSTEXPR_IF(alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)) ptr = ::operator new( sizeof(T) * n, std::align_val_t{alignof(T)}, std::nothrow); else #endif // RANGES_CXX_ALIGNED_NEW ptr = ::operator new(sizeof(T) * n, std::nothrow); } return {static_cast(ptr), static_cast(n)}; } template std::pair get_temporary_buffer(D count) noexcept { RANGES_EXPECT(count >= 0); return detail::get_temporary_buffer_impl(static_cast(count)); } struct return_temporary_buffer { template void operator()(T * p) const { #if RANGES_CXX_ALIGNED_NEW < RANGES_CXX_ALIGNED_NEW_17 static_assert(alignof(T) <= alignof(std::max_align_t), "Sorry: over-aligned types are supported only with C++17."); #else // RANGES_CXX_ALIGNED_NEW if(RANGES_CONSTEXPR_IF(alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)) ::operator delete(p, std::align_val_t{alignof(T)}); else #endif // RANGES_CXX_ALIGNED_NEW ::operator delete(p); } }; template auto make_unique(Args &&... args) -> CPP_ret(std::unique_ptr)( // requires(!std::is_array::value)) { return std::unique_ptr{new T(static_cast(args)...)}; } } // namespace detail /// \endcond /// \addtogroup group-utility /// @{ template struct raw_storage_iterator { private: CPP_assert(output_iterator); CPP_assert(std::is_lvalue_reference>()); O out_; public: using difference_type = iter_difference_t; raw_storage_iterator() = default; explicit raw_storage_iterator(O out) : out_(std::move(out)) {} raw_storage_iterator & operator*() noexcept { return *this; } CPP_member auto operator=(Val const & val) -> CPP_ret(raw_storage_iterator &)( // requires copy_constructible) { ::new((void *)std::addressof(*out_)) Val(val); return *this; } CPP_member auto operator=(Val && val) -> CPP_ret(raw_storage_iterator &)( // requires move_constructible) { ::new((void *)std::addressof(*out_)) Val(std::move(val)); return *this; } raw_storage_iterator & operator++() { ++out_; return *this; } CPP_member auto operator++(int) -> CPP_ret(void)( // requires(!forward_iterator)) { ++out_; } CPP_member auto operator++(int) -> CPP_ret(raw_storage_iterator)( // requires forward_iterator) { auto tmp = *this; ++out_; return tmp; } O base() const { return out_; } }; template struct iterator_wrapper { private: CPP_assert(input_or_output_iterator); mutable I * i_ = nullptr; public: using difference_type = iter_difference_t; iterator_wrapper() = default; iterator_wrapper(iterator_wrapper const & that) : i_(that.i_) { that.i_ = nullptr; } iterator_wrapper & operator=(iterator_wrapper const & that) { i_ = that.i_; that.i_ = nullptr; return *this; } iterator_wrapper(I & i) : i_(std::addressof(i)) {} // clang-format off auto CPP_auto_fun(operator*)()(const) ( return **i_ ) // clang-format on iterator_wrapper & operator++() { ++*i_; return *this; } void operator++(int) { ++*i_; } I base() const { return *i_; } }; template auto iter_ref(I & i) -> CPP_ret(iterator_wrapper)( // requires input_or_output_iterator) { return i; } template struct readable_traits> : meta::if_c<(bool)input_iterator, readable_traits, meta::nil_> {}; template struct raw_buffer { private: Val * begin_; raw_storage_iterator rsi_; public: explicit raw_buffer(Val * first) : begin_(first) , rsi_(first) {} raw_buffer(raw_buffer &&) = default; raw_buffer(raw_buffer const &) = delete; ~raw_buffer() { for(; begin_ != rsi_.base(); ++begin_) begin_->~Val(); } iterator_wrapper> begin() { return ranges::iter_ref(rsi_); } }; template raw_buffer make_raw_buffer(Val * val) { return raw_buffer(val); } /// @} } // namespace ranges #endif