|
- /// \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 <cstdint>
- #include <memory>
- #include <type_traits>
- #include <utility>
-
- #include <meta/meta.hpp>
-
- #include <range/v3/detail/config.hpp>
- #include <range/v3/iterator/concepts.hpp>
- #include <range/v3/iterator/traits.hpp>
- #include <range/v3/utility/polymorphic_cast.hpp>
-
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<typename T>
- std::pair<T *, std::ptrdiff_t> get_temporary_buffer_impl(
- std::size_t count) noexcept
- {
- RANGES_EXPECT(count >= 0);
- std::size_t n = static_cast<std::size_t>(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<T *>(ptr), static_cast<std::ptrdiff_t>(n)};
- }
-
- template<typename T, typename D>
- std::pair<T *, std::ptrdiff_t> get_temporary_buffer(D count) noexcept
- {
- RANGES_EXPECT(count >= 0);
- return detail::get_temporary_buffer_impl<T>(static_cast<std::size_t>(count));
- }
-
- struct return_temporary_buffer
- {
- template<typename T>
- 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<typename T, typename... Args>
- auto make_unique(Args &&... args) -> CPP_ret(std::unique_ptr<T>)( //
- requires(!std::is_array<T>::value))
- {
- return std::unique_ptr<T>{new T(static_cast<Args &&>(args)...)};
- }
- } // namespace detail
- /// \endcond
-
- /// \addtogroup group-utility
- /// @{
- template<typename O, typename Val>
- struct raw_storage_iterator
- {
- private:
- CPP_assert(output_iterator<O, Val>);
- CPP_assert(std::is_lvalue_reference<iter_reference_t<O>>());
- O out_;
-
- public:
- using difference_type = iter_difference_t<O>;
- 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<Val>)
- {
- ::new((void *)std::addressof(*out_)) Val(val);
- return *this;
- }
- CPP_member
- auto operator=(Val && val) -> CPP_ret(raw_storage_iterator &)( //
- requires move_constructible<Val>)
- {
- ::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<O>))
- {
- ++out_;
- }
- CPP_member
- auto operator++(int) -> CPP_ret(raw_storage_iterator)( //
- requires forward_iterator<O>)
- {
- auto tmp = *this;
- ++out_;
- return tmp;
- }
- O base() const
- {
- return out_;
- }
- };
-
- template<typename I>
- struct iterator_wrapper
- {
- private:
- CPP_assert(input_or_output_iterator<I>);
- mutable I * i_ = nullptr;
-
- public:
- using difference_type = iter_difference_t<I>;
- 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<typename I>
- auto iter_ref(I & i) -> CPP_ret(iterator_wrapper<I>)( //
- requires input_or_output_iterator<I>)
- {
- return i;
- }
-
- template<typename I>
- struct readable_traits<iterator_wrapper<I>>
- : meta::if_c<(bool)input_iterator<I>, readable_traits<I>, meta::nil_>
- {};
-
- template<typename Val>
- struct raw_buffer
- {
- private:
- Val * begin_;
- raw_storage_iterator<Val *, Val> 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<raw_storage_iterator<Val *, Val>> begin()
- {
- return ranges::iter_ref(rsi_);
- }
- };
-
- template<typename Val>
- raw_buffer<Val> make_raw_buffer(Val * val)
- {
- return raw_buffer<Val>(val);
- }
- /// @}
- } // namespace ranges
-
- #endif
|