blob: 6a98d4223b368e6e3f59c10f4b45a6dc12b223d6 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Standalone implementation of std::unique_ptr.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H
#include "hdr/types/size_t.h"
#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/new.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/CPP/utility.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
/// A wrapper for deleting objects by default.
template <typename T> struct default_delete {
LIBC_INLINE constexpr default_delete() = default;
template <typename U, typename = enable_if_t<is_convertible_v<U *, T *>>>
LIBC_INLINE constexpr default_delete(const default_delete<U> &) {}
LIBC_INLINE constexpr void operator()(T *ptr) const {
static_assert(sizeof(T) > 0, "cannot delete an incomplete type");
delete ptr;
}
};
/// A wrapper for deleting array objects by default.
template <typename T> struct default_delete<T[]> {
LIBC_INLINE constexpr default_delete() = default;
template <typename U,
typename = enable_if_t<is_convertible_v<U (*)[], T (*)[]>>>
LIBC_INLINE constexpr default_delete(const default_delete<U[]> &) {}
template <typename U,
typename = enable_if_t<is_convertible_v<U (*)[], T (*)[]>>>
LIBC_INLINE constexpr void operator()(U *ptr) const {
static_assert(sizeof(U) > 0, "cannot delete an incomplete type");
delete[] ptr;
}
};
/// A smart pointer that owns and manages another object through a pointer.
template <typename T, typename Deleter = default_delete<T>>
class LIBC_TRIVIAL_ABI unique_ptr {
T *ptr = nullptr;
LIBC_NO_UNIQUE_ADDRESS Deleter deleter;
public:
using element_type = T;
using deleter_type = Deleter;
using pointer = T *;
LIBC_INLINE constexpr unique_ptr() = default;
LIBC_INLINE constexpr unique_ptr(nullptr_t) : ptr(nullptr) {}
LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {}
LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d)
: ptr(p), deleter(d) {}
LIBC_INLINE constexpr unique_ptr(pointer p, deleter_type &&d)
: ptr(p), deleter(move(d)) {}
// Move constructor
LIBC_INLINE constexpr unique_ptr(unique_ptr &&other)
: ptr(other.release()), deleter(forward<Deleter>(other.get_deleter())) {}
// Move assignment
LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr &&other) {
reset(other.release());
deleter = forward<Deleter>(other.get_deleter());
return *this;
}
// Conversion move constructor
template <typename U, typename E,
typename = enable_if_t<
is_convertible_v<typename unique_ptr<U, E>::pointer, pointer> &&
!is_array<U>::value && is_convertible_v<E, Deleter>>>
LIBC_INLINE constexpr unique_ptr(unique_ptr<U, E> &&other)
: ptr(other.release()), deleter(forward<E>(other.get_deleter())) {}
// Conversion move assignment
template <typename U, typename E,
typename = enable_if_t<
is_convertible_v<typename unique_ptr<U, E>::pointer, pointer> &&
!is_array<U>::value && is_assignable_v<Deleter &, E &&>>>
LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr<U, E> &&other) {
reset(other.release());
deleter = forward<E>(other.get_deleter());
return *this;
}
// Disable copy
unique_ptr(const unique_ptr &) = delete;
unique_ptr &operator=(const unique_ptr &) = delete;
LIBC_INLINE ~unique_ptr() { reset(); }
LIBC_INLINE constexpr pointer get() const { return ptr; }
LIBC_INLINE constexpr deleter_type &get_deleter() { return deleter; }
LIBC_INLINE constexpr const deleter_type &get_deleter() const {
return deleter;
}
LIBC_INLINE constexpr explicit operator bool() const {
return ptr != nullptr;
}
LIBC_INLINE constexpr pointer release() {
pointer temp = ptr;
ptr = nullptr;
return temp;
}
LIBC_INLINE constexpr void reset(pointer p = pointer()) {
pointer old_ptr = ptr;
ptr = p;
if (old_ptr)
deleter(old_ptr);
}
LIBC_INLINE constexpr typename add_lvalue_reference<T>::type
operator*() const {
LIBC_ASSERT(ptr != nullptr);
return *ptr;
}
LIBC_INLINE constexpr pointer operator->() const {
LIBC_ASSERT(ptr != nullptr);
return ptr;
}
};
/// A smart pointer that owns and manages an array of objects through a pointer.
template <typename T, typename Deleter>
class LIBC_TRIVIAL_ABI unique_ptr<T[], Deleter> {
T *ptr = nullptr;
LIBC_NO_UNIQUE_ADDRESS Deleter deleter;
public:
using element_type = T;
using deleter_type = Deleter;
using pointer = T *;
LIBC_INLINE constexpr unique_ptr() = default;
LIBC_INLINE constexpr unique_ptr(nullptr_t) : ptr(nullptr) {}
LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {}
LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d)
: ptr(p), deleter(d) {}
LIBC_INLINE constexpr unique_ptr(pointer p, deleter_type &&d)
: ptr(p), deleter(move(d)) {}
// Move constructor
LIBC_INLINE constexpr unique_ptr(unique_ptr &&other)
: ptr(other.release()), deleter(forward<Deleter>(other.get_deleter())) {}
// Move assignment
LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr &&other) {
reset(other.release());
deleter = forward<Deleter>(other.get_deleter());
return *this;
}
// Disable copy
unique_ptr(const unique_ptr &) = delete;
unique_ptr &operator=(const unique_ptr &) = delete;
LIBC_INLINE ~unique_ptr() { reset(); }
LIBC_INLINE constexpr pointer get() const { return ptr; }
LIBC_INLINE constexpr deleter_type &get_deleter() { return deleter; }
LIBC_INLINE constexpr const deleter_type &get_deleter() const {
return deleter;
}
LIBC_INLINE constexpr explicit operator bool() const {
return ptr != nullptr;
}
LIBC_INLINE constexpr pointer release() {
pointer temp = ptr;
ptr = nullptr;
return temp;
}
LIBC_INLINE constexpr void reset(pointer p = pointer()) {
pointer old_ptr = ptr;
ptr = p;
if (old_ptr)
deleter(old_ptr);
}
LIBC_INLINE constexpr T &operator[](size_t i) const {
LIBC_ASSERT(ptr != nullptr);
return ptr[i];
}
};
} // namespace cpp
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H