From 5068d34c08f951a7ea6257d305a1627b09a95817 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 19:44:55 +0200 Subject: Adding upstream version 0.11.1. Signed-off-by: Daniel Baumann --- src/third-party/scnlib/include/scn/util/memory.h | 404 +++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 src/third-party/scnlib/include/scn/util/memory.h (limited to 'src/third-party/scnlib/include/scn/util/memory.h') diff --git a/src/third-party/scnlib/include/scn/util/memory.h b/src/third-party/scnlib/include/scn/util/memory.h new file mode 100644 index 0000000..9dfb970 --- /dev/null +++ b/src/third-party/scnlib/include/scn/util/memory.h @@ -0,0 +1,404 @@ +// Copyright 2017 Elias Kosunen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is a part of scnlib: +// https://github.com/eliaskosunen/scnlib + +#ifndef SCN_UTIL_MEMORY_H +#define SCN_UTIL_MEMORY_H + +#include "meta.h" + +#include +#include + +SCN_GCC_PUSH +SCN_GCC_IGNORE("-Wnoexcept") +#include +SCN_GCC_POP + +#if SCN_MSVC && SCN_HAS_STRING_VIEW +#include +#endif + +namespace scn { + SCN_BEGIN_NAMESPACE + + namespace detail { + template + struct pointer_traits; + + template + struct pointer_traits { + using pointer = T*; + using element_type = T; + using difference_type = std::ptrdiff_t; + + template + using rebind = U*; + + template ::value>::type* = + nullptr> + static constexpr pointer pointer_to(U& r) noexcept + { + return &r; + } + }; + + template + constexpr T* to_address_impl(T* p, priority_tag<2>) noexcept + { + return p; + } + template + SCN_CONSTEXPR14 auto to_address_impl(const Ptr& p, + priority_tag<1>) noexcept + -> decltype(::scn::detail::pointer_traits::to_address(p)) + { + return ::scn::detail::pointer_traits::to_address(p); + } + template + constexpr auto to_address_impl(const Ptr& p, priority_tag<0>) noexcept + -> decltype(::scn::detail::to_address_impl(p.operator->(), + priority_tag<2>{})) + { + return ::scn::detail::to_address_impl(p.operator->(), + priority_tag<2>{}); + } + + template + constexpr auto to_address(Ptr&& p) noexcept + -> decltype(::scn::detail::to_address_impl(SCN_FWD(p), + priority_tag<2>{})) + { + return ::scn::detail::to_address_impl(SCN_FWD(p), + priority_tag<2>{}); + } + +#if SCN_WINDOWS + template + SCN_CONSTEXPR14 auto to_address_safe(I&& p, B begin, E end) noexcept + -> decltype(to_address(SCN_FWD(p))) + { + if (p >= begin && p < end) { + return to_address(SCN_FWD(p)); + } + if (begin == end) { + return to_address(SCN_FWD(p)); + } + if (p == end) { + return to_address(SCN_FWD(p) - 1) + 1; + } + SCN_ENSURE(false); + SCN_UNREACHABLE; + } +#else + template + SCN_CONSTEXPR14 auto to_address_safe(I&& p, B, E) noexcept + -> decltype(to_address(SCN_FWD(p))) + { + return to_address(SCN_FWD(p)); + } +#endif + + // Workaround for MSVC _String_view_iterator +#if SCN_MSVC && SCN_HAS_STRING_VIEW + template + struct pointer_traits> { + using iterator = std::_String_view_iterator; + using pointer = typename iterator::pointer; + using element_type = typename iterator::value_type; + using difference_type = typename iterator::difference_type; + + static constexpr pointer to_address(const iterator& it) noexcept + { + // operator-> of _String_view_iterator + // is checked for past-the-end dereference, + // even though operator-> isn't dereferencing anything :))) + return it._Unwrapped(); + } + }; +#endif + + template + constexpr T* launder(T* p) noexcept + { +#if SCN_HAS_LAUNDER + return std::launder(p); +#else + return p; +#endif + } + + template + void uninitialized_fill(ForwardIt first, + ForwardIt last, + const T& value, + std::true_type) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + const auto dist = static_cast(std::distance(first, last)) * + sizeof(value_type); + std::memset(&*first, static_cast(value), dist); + } + template + void uninitialized_fill(ForwardIt first, + ForwardIt last, + const T& value, + std::false_type) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + ForwardIt current = first; + for (; current != last; ++current) { + ::new (static_cast(std::addressof(*current))) + value_type(value); + } + } + template + void uninitialized_fill(ForwardIt first, + ForwardIt last, + const T& value) noexcept + { + constexpr bool B = std::is_trivially_copyable::value && + std::is_pointer::value && + sizeof(T) == 1; + return uninitialized_fill(first, last, value, + std::integral_constant{}); + } + + template + void uninitialized_fill_default_construct(ForwardIt first, + ForwardIt last) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + ForwardIt current = first; + for (; current != last; ++current) { + ::new (static_cast(std::addressof(*current))) value_type; + } + } + template + void uninitialized_fill_value_init(ForwardIt first, + ForwardIt last) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + ForwardIt current = first; + for (; current != last; ++current) { + ::new (static_cast(std::addressof(*current))) + value_type(); + } + } + + template ::value_type>::value>::type* = nullptr> + ForwardIt uninitialized_copy(InputIt first, + InputIt last, + ForwardIt d_first) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + ForwardIt current = d_first; + for (; first != last; ++first, (void)++current) { + ::new (static_cast(std::addressof(*current))) + value_type(*first); + } + return current; + } + template ::value_type>::value>::type* = nullptr> + ForwardIt uninitialized_copy(InputIt first, + InputIt last, + ForwardIt d_first) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + using pointer = typename std::iterator_traits::pointer; + auto ptr = + std::memcpy(std::addressof(*d_first), std::addressof(*first), + static_cast(std::distance(first, last)) * + sizeof(value_type)); + return ForwardIt{static_cast(ptr)}; + } + + template ::value_type>::value>::type* = nullptr> + ForwardIt uninitialized_move(InputIt first, + InputIt last, + ForwardIt d_first) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + ForwardIt current = d_first; + for (; first != last; ++first, (void)++current) { + ::new (static_cast(std::addressof(*current))) + value_type(std::move(*first)); + } + return current; + } + template ::value_type>::value>::type* = nullptr> + ForwardIt uninitialized_move(InputIt first, + InputIt last, + ForwardIt d_first) noexcept + { + using value_type = + typename std::iterator_traits::value_type; + using pointer = typename std::iterator_traits::pointer; + auto ptr = + std::memcpy(std::addressof(*d_first), std::addressof(*first), + static_cast(std::distance(first, last)) * + sizeof(value_type)); + return ForwardIt(static_cast(ptr)); + } + + template + class SCN_TRIVIAL_ABI erased_storage { + public: + using value_type = T; + using pointer = T*; + using storage_type = unsigned char[sizeof(T)]; + + constexpr erased_storage() noexcept = default; + + erased_storage(T val) noexcept( + std::is_nothrow_move_constructible::value) + : m_ptr(::new (static_cast(&m_data)) T(SCN_MOVE(val))) + { + } + + erased_storage(const erased_storage& other) + : m_ptr(other ? ::new (static_cast(&m_data)) + T(other.get()) + : nullptr) + { + } + erased_storage& operator=(const erased_storage& other) + { + _destruct(); + if (other) { + m_ptr = ::new (static_cast(&m_data)) T(other.get()); + } + return *this; + } + + erased_storage(erased_storage&& other) noexcept + : m_ptr(other ? ::new (static_cast(&m_data)) + T(SCN_MOVE(other.get())) + : nullptr) + { + other.m_ptr = nullptr; + } + erased_storage& operator=(erased_storage&& other) noexcept + { + _destruct(); + if (other) { + m_ptr = ::new (static_cast(&m_data)) + T(SCN_MOVE(other.get())); + other.m_ptr = nullptr; + } + return *this; + } + + ~erased_storage() noexcept + { + _destruct(); + } + + SCN_NODISCARD constexpr bool has_value() const noexcept + { + return m_ptr != nullptr; + } + constexpr explicit operator bool() const noexcept + { + return has_value(); + } + + SCN_CONSTEXPR14 T& get() noexcept + { + SCN_EXPECT(has_value()); + return _get(); + } + SCN_CONSTEXPR14 const T& get() const noexcept + { + SCN_EXPECT(has_value()); + return _get(); + } + + SCN_CONSTEXPR14 T& operator*() noexcept + { + SCN_EXPECT(has_value()); + return _get(); + } + SCN_CONSTEXPR14 const T& operator*() const noexcept + { + SCN_EXPECT(has_value()); + return _get(); + } + + SCN_CONSTEXPR14 T* operator->() noexcept + { + return m_ptr; + } + SCN_CONSTEXPR14 const T* operator->() const noexcept + { + return m_ptr; + } + + private: + void _destruct() + { + if (m_ptr) { + _get().~T(); + } + m_ptr = nullptr; + } + static pointer _toptr(storage_type& data) + { + return ::scn::detail::launder( + reinterpret_cast(reinterpret_cast(data.data()))); + } + SCN_CONSTEXPR14 T& _get() noexcept + { + return *m_ptr; + } + SCN_CONSTEXPR14 const T& _get() const noexcept + { + return *m_ptr; + } + + alignas(T) storage_type m_data{}; + pointer m_ptr{nullptr}; + }; + } // namespace detail + + SCN_END_NAMESPACE +} // namespace scn + +#endif -- cgit v1.2.3