citrus/include/bpstd/memory.hpp
Robert Sebastian Herlim e27ed026dd Initial commit of CITRUS
2021-10-04 10:56:53 +09:00

262 lines
8.3 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// \file memory.hpp
///
/// \brief This header provides definitions from the C++ header <memory>
////////////////////////////////////////////////////////////////////////////////
/*
The MIT License (MIT)
Copyright (c) 2020 Matthew Rodusek All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef BPSTD_MEMORY_HPP
#define BPSTD_MEMORY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "detail/config.hpp"
#include "type_traits.hpp" // conditional_t, void_t
#include "utility.hpp" // forward
#include <memory> // std::unique_ptr
#include <cstddef> // std::size_t
#include <type_traits> // std::declval
BPSTD_COMPILER_DIAGNOSTIC_PREAMBLE
namespace bpstd {
namespace detail {
template <typename T>
struct make_unique_result
{
using object = T;
};
template <typename T>
struct make_unique_result<T[]>
{
using unbounded_array = T[];
};
template <typename T, std::size_t N>
struct make_unique_result<T[N]>
{
using bounded_array = T[N];
};
}
/// \brief Constructs an object of type T and wraps it in a std::unique_ptr
///
/// Constructs a non-array type T. The arguments args are passed to the
/// constructor of T. This overload only participates in overload resolution
/// if T is not an array type.
///
/// \tparam T the type to construct
/// \param args the arguments to forward to T's constructor
/// \return the unique_ptr
template <typename T, typename...Args>
std::unique_ptr<typename detail::make_unique_result<T>::object>
make_unique(Args&&...args);
/// \brief Constructs an object of type T[] and wraps it in a std::unique_ptr
///
/// Constructs an array of unknown bound T. This overload only participates
/// in overload resolution if T is an array of unknown bound.
///
/// \tparam T the type to construct
/// \param size the size of the array
/// \return the unique_ptr
template <typename T>
std::unique_ptr<typename detail::make_unique_result<T>::unbounded_array>
make_unique(std::size_t size);
// Construction of arrays of known bound is disallowed
template <typename T>
std::unique_ptr<typename detail::make_unique_result<T>::bounded_array>
make_unique() = delete;
/// \brief Constructs an object of type T through default-initialization
/// and wraps it in a std::unique_ptr
///
/// Constructs a non-array type T. This overload only participates in
/// overload resolution if T is not an array type. The object is
/// default-initialised, which may mean it will need to be overwritten before
/// it is legal to be read
///
/// \tparam T the type to construct
/// \return the unique_ptr
template <typename T>
std::unique_ptr<typename detail::make_unique_result<T>::object>
make_unique_for_overwrite();
/// \brief Constructs an object of type T[] through default-initialization
/// and wraps it in a std::unique_ptr
///
/// Constructs an array of unknown bound T. This overload only participates
/// in overload resolution if T is an array of unknown bound. The array is
/// default-initialised, which may mean it will need to be overwritten before
/// it is legal to be read
///
/// \tparam T the type to construct
/// \return the unique_ptr
template <typename T>
std::unique_ptr<typename detail::make_unique_result<T>::unbounded_array>
make_unique_for_overwrite(std::size_t size);
// Construction of arrays of known bound is disallowed
template <typename T>
std::unique_ptr<typename detail::make_unique_result<T>::bounded_array>
make_unique_for_overwrite() = delete;
//----------------------------------------------------------------------------
namespace detail {
template <typename T, typename = void>
struct has_to_address : false_type{};
template <typename T>
struct has_to_address<T,void_t<decltype(std::pointer_traits<T>::to_address(std::declval<const T&>()))>>
: true_type{};
//--------------------------------------------------------------------------
template <bool, typename T>
struct operator_deref
{
using type = decltype(std::declval<const T&>().operator->());
};
template <typename T>
struct operator_deref<true, T>{};
//--------------------------------------------------------------------------
template <typename T, typename = void>
struct to_address_result
: operator_deref<std::is_pointer<remove_cvref_t<T>>::value, T>{};
template <typename T>
struct to_address_result<T,void_t<decltype(std::pointer_traits<T>::to_address(std::declval<const T&>()))>>
{
using type = decltype(std::pointer_traits<T>::to_address(std::declval<const T&>()));
};
template <typename T>
using to_address_result_t = typename to_address_result<T>::type;
} // namespace detail
/// \{
/// \brief Converts a pointer-like type to a raw pointer by recursively
/// calling to_address on it
///
/// \param p the pointer-like type
/// \return the pointer
template <typename T>
constexpr T* to_address(T* p) noexcept;
template <typename T>
constexpr detail::to_address_result_t<T> to_address(const T& p) noexcept;
/// \}
} // namespace bpstd
template <typename T, typename...Args>
inline BPSTD_INLINE_VISIBILITY
std::unique_ptr<typename bpstd::detail::make_unique_result<T>::object>
bpstd::make_unique(Args&&...args)
{
return std::unique_ptr<T>{new T(bpstd::forward<Args>(args)...)};
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
std::unique_ptr<typename bpstd::detail::make_unique_result<T>::unbounded_array>
bpstd::make_unique(std::size_t size)
{
return std::unique_ptr<T>{new remove_extent_t<T>[size]()};
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
std::unique_ptr<typename bpstd::detail::make_unique_result<T>::object>
bpstd::make_unique_for_overwrite()
{
return std::unique_ptr<T>{new T};
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
std::unique_ptr<typename bpstd::detail::make_unique_result<T>::unbounded_array>
bpstd::make_unique_for_overwrite(std::size_t size)
{
return std::unique_ptr<T>{new remove_extent_t<T>[size]};
}
namespace bpstd {
namespace detail {
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
auto to_address_impl(const T& p, std::true_type)
-> decltype(std::pointer_traits<T>::to_address(std::declval<const T&>()))
{
return to_address(std::pointer_traits<T>::to_address(p));
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
auto to_address_impl(const T& p, std::false_type)
-> decltype(std::declval<const T&>().operator->())
{
return to_address(p.operator->());
}
} // namespace detail
} // namespace bpstd
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
T* bpstd::to_address(T* p)
noexcept
{
static_assert(
!std::is_function<T>::value,
"T* must not be a function pointer"
);
return p;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::detail::to_address_result_t<T>
bpstd::to_address(const T& p)
noexcept
{
return detail::to_address_impl(p, detail::has_to_address<T>{});
}
BPSTD_COMPILER_DIAGNOSTIC_POSTAMBLE
#endif /* BPSTD_MEMORY_HPP */