| // Part of the Crubit project, under the Apache License v2.0 with LLVM | |
| // Exceptions. See /LICENSE for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // Mock of standard library <memory> header. | |
| #ifndef CRUBIT_NULLABILITY_TEST_MEMORY_ | |
| #define CRUBIT_NULLABILITY_TEST_MEMORY_ | |
| #include <type_traits> | |
| #include <utility> | |
| namespace std { | |
| // Adding some definitions here for convenience that really belong in other | |
| // headers. | |
| using nullptr_t = decltype(nullptr); | |
| using size_t = decltype(sizeof(int)); | |
| template <class T> | |
| struct remove_extent { using type = T; }; | |
| template <class T> | |
| struct remove_extent<T[]> { using type = T; }; | |
| template <class T, size_t N> | |
| struct remove_extent<T[N]> { using type = T; }; | |
| template <class T> struct default_delete{}; | |
| template <class T> struct allocator{}; | |
| template< class... > | |
| using void_t = void; | |
| template <class T, class Deleter, class = void> | |
| struct __underlying_ptr_type { | |
| using type = T *; | |
| }; | |
| template <class T, class Deleter> | |
| // The standard says we should apply `std::remove_reference` to `Deleter`, | |
| // but we don't need this for our tests, so we omit it for simplicity. | |
| struct __underlying_ptr_type<T, Deleter, | |
| std::void_t<typename Deleter::pointer>> { | |
| using type = typename Deleter::pointer; | |
| }; | |
| template <class T, class Deleter = default_delete<T>> | |
| class unique_ptr { | |
| public: | |
| using pointer = __underlying_ptr_type<T, Deleter>::type; | |
| unique_ptr(); | |
| unique_ptr(nullptr_t); | |
| unique_ptr(pointer); | |
| // We're restricting ourselves to just one possible case for the deleter | |
| // parameter. | |
| unique_ptr(pointer, const Deleter &); | |
| unique_ptr(unique_ptr &&); | |
| template <class OtherT, class OtherDeleter> | |
| unique_ptr(unique_ptr<OtherT, OtherDeleter> &&); | |
| unique_ptr(const unique_ptr &) = delete; | |
| // Make sure `unique_ptr` is not trivially destructible so that the AST for | |
| // expressions using this mock look the same as for the real class. | |
| ~unique_ptr(); | |
| unique_ptr &operator=(unique_ptr &&); | |
| template <class OtherT, class OtherDeleter> | |
| unique_ptr &operator=(unique_ptr<OtherT, OtherDeleter> &&); | |
| unique_ptr &operator=(nullptr_t); | |
| unique_ptr &operator=(const unique_ptr &) = delete; | |
| T &operator*() const; | |
| T *operator->() const; | |
| pointer release(); | |
| void reset(pointer p = pointer()); | |
| void swap(unique_ptr &); | |
| pointer get() const; | |
| explicit operator bool() const; | |
| }; | |
| // Array specialization of `unique_ptr`. We only introduce the members that are | |
| // used in tests. | |
| template <class T, class Deleter> | |
| class unique_ptr<T[], Deleter> { | |
| public: | |
| using pointer = T*; | |
| unique_ptr(); | |
| template <class ArrayT> | |
| explicit unique_ptr(ArrayT); | |
| template <class ArrayT> | |
| explicit unique_ptr(ArrayT, const Deleter &); | |
| unique_ptr(const unique_ptr &) = delete; | |
| ~unique_ptr(); | |
| template <class ArrayT> | |
| void reset(ArrayT); | |
| void reset(nullptr_t = nullptr); | |
| pointer get() const; | |
| T &operator[](size_t) const; | |
| }; | |
| // We're restricting ourselves to just some of the overloads that are required | |
| // to provide sufficient test coverage. | |
| template <class T, class... Args, enable_if<!__is_array(T), int>::type = 0> | |
| unique_ptr<T> make_unique(Args&&... args) { | |
| return unique_ptr<T>(new T(std::forward<Args>(args)...)); | |
| } | |
| template <class T, enable_if<__is_unbounded_array_v<T>, int>::type = 0> | |
| unique_ptr<T> make_unique(size_t n) { | |
| using ET = remove_extent<T>::type; | |
| return unique_ptr<T>(new ET[n]); | |
| } | |
| template <class T> | |
| unique_ptr<T> make_unique_for_overwrite(); | |
| template <class T> | |
| unique_ptr<T> make_unique_for_overwrite(size_t); | |
| template <class T, class Deleter> | |
| void swap(unique_ptr<T, Deleter> &, unique_ptr<T, Deleter> &); | |
| template <class T> | |
| bool operator==(const unique_ptr<T> &, std::nullptr_t); | |
| // C++20 and later do not define the following overloads because they are | |
| // provided by rewritten candidates instead. | |
| #if __cplusplus < 202002L | |
| template <class T> | |
| bool operator==(std::nullptr_t, const unique_ptr<T> &); | |
| #endif // __cplusplus < 202002L | |
| template <class T> class weak_ptr; | |
| // This definition of `shared_ptr` only introduces the members that are used in | |
| // tests. | |
| template <class T> | |
| class shared_ptr { | |
| public: | |
| using element_type = typename remove_extent<T>::type; | |
| shared_ptr(); | |
| template <class OtherT> | |
| shared_ptr(OtherT *); | |
| template <class Deleter> | |
| shared_ptr(nullptr_t, Deleter); | |
| template <class Deleter, class Alloc> | |
| shared_ptr(nullptr_t, Deleter, Alloc); | |
| template <class OtherT, class Deleter, class Alloc> | |
| shared_ptr(OtherT *, Deleter, Alloc); | |
| template <class OtherT> | |
| shared_ptr(const shared_ptr<OtherT> &, element_type *); | |
| template <class OtherT> | |
| shared_ptr(shared_ptr<OtherT> &&, element_type *); | |
| shared_ptr(const shared_ptr &); | |
| template <class OtherT> | |
| explicit shared_ptr(const weak_ptr<OtherT> &); | |
| template <class OtherT, class Deleter> | |
| explicit shared_ptr(unique_ptr<OtherT, Deleter> &&); | |
| ~shared_ptr(); | |
| shared_ptr &operator=(const shared_ptr &); | |
| template <class OtherT> | |
| shared_ptr &operator=(const shared_ptr<OtherT> &); | |
| T& operator*() const; | |
| void reset(); | |
| template <class OtherT> | |
| void reset(OtherT *); | |
| template <class OtherT, class Deleter> | |
| void reset(OtherT *, Deleter); | |
| template <class OtherT, class Deleter, class Alloc> | |
| void reset(OtherT *, Deleter, Alloc); | |
| element_type* get() const; | |
| explicit operator bool() const; | |
| }; | |
| // We're restricting ourselves to just some of the overloads that are required | |
| // to provide sufficient test coverage. | |
| template <class T> | |
| shared_ptr<T> make_shared(); | |
| template <class T, class... Args> | |
| shared_ptr<T> make_shared(Args &&...args); | |
| template <class T> | |
| shared_ptr<T> make_shared_for_overwrite(); | |
| template <class T> | |
| shared_ptr<T> make_shared_for_overwrite(size_t); | |
| template <class T, class Alloc> | |
| shared_ptr<T> allocate_shared(const Alloc &); | |
| template <class T, class Alloc, class... Args> | |
| shared_ptr<T> allocate_shared(const Alloc &, Args &&...args); | |
| template <class T, class Alloc> | |
| shared_ptr<T> allocate_shared_for_overwrite(const Alloc &); | |
| template <class T, class Alloc> | |
| shared_ptr<T> allocate_shared_for_overwrite(const Alloc &, size_t); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> static_pointer_cast(const shared_ptr<SrcT> &); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> static_pointer_cast(const shared_ptr<SrcT> &&); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> dynamic_pointer_cast(const shared_ptr<SrcT> &); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> dynamic_pointer_cast(const shared_ptr<SrcT> &&); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> const_pointer_cast(const shared_ptr<SrcT> &); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> const_pointer_cast(const shared_ptr<SrcT> &&); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> reinterpret_pointer_cast(const shared_ptr<SrcT> &); | |
| template <class DestT, class SrcT> | |
| shared_ptr<DestT> reinterpret_pointer_cast(const shared_ptr<SrcT> &&); | |
| template <class T1, class T2> | |
| bool operator==(const shared_ptr<T1> &, const shared_ptr<T2> &); | |
| template <class T> | |
| bool operator==(const shared_ptr<T> &, std::nullptr_t); | |
| // C++20 and later do not define the following overloads because they are | |
| // provided by rewritten candidates instead. | |
| #if __cplusplus < 202002L | |
| template <class T1, class T2> | |
| bool operator!=(const shared_ptr<T1> &, const shared_ptr<T2> &); | |
| template <class T> | |
| bool operator==(std::nullptr_t, const shared_ptr<T> &); | |
| template <class T> | |
| bool operator!=(const shared_ptr<T> &, std::nullptr_t); | |
| template <class T> | |
| bool operator!=(std::nullptr_t, const shared_ptr<T> &); | |
| #endif // __cplusplus < 202002L | |
| // This mock only provides the definitions needed to test that | |
| // `weak_ptr::lock()` returns a nullable pointer. | |
| template <class T> class weak_ptr { | |
| public: | |
| template <class OtherT> | |
| weak_ptr(const shared_ptr<OtherT> &); | |
| shared_ptr<T> lock() const; | |
| }; | |
| } // namespace std | |
| #endif // CRUBIT_NULLABILITY_TEST_MEMORY_ |