diff --git a/ctl/shared_ptr.h b/ctl/shared_ptr.h index 983e33816..718ae9f98 100644 --- a/ctl/shared_ptr.h +++ b/ctl/shared_ptr.h @@ -25,10 +25,13 @@ struct shared_control constexpr shared_control() noexcept : shared(0), weak(0) { } + shared_control(const shared_control&) = delete; + virtual ~shared_control() { } + void add_shared() noexcept; void release_shared() noexcept; void add_weak() noexcept; @@ -46,7 +49,7 @@ struct shared_pointer : shared_control { T* p; - static shared_pointer* make(T* p) + static shared_pointer* make(T* const p) { auto p2 = unique_ptr(p); auto r = new shared_pointer(p2.release()); @@ -54,7 +57,7 @@ struct shared_pointer : shared_control } private: - shared_pointer(T* p) noexcept : p(p) + explicit constexpr shared_pointer(T* const p) noexcept : p(p) { } @@ -79,29 +82,136 @@ struct bad_weak_ptr : ctl::exception } }; +// TODO(mrdomino): typename D = default_delete template class shared_ptr { public: + using element_type = T; // TODO(mrdomino): remove extent? + constexpr shared_ptr(nullptr_t = nullptr) noexcept : p(nullptr), ctl(nullptr) { } - shared_ptr(T* const p) : p(p), ctl(__::shared_pointer::make(p)) + + explicit shared_ptr(auto* const p) : p(p), ctl(__::shared_pointer::make(p)) { } + shared_ptr(const shared_ptr& r) noexcept : p(r.p), ctl(r.ctl) + { + if (ctl) + ctl->add_shared(); + } + + shared_ptr(shared_ptr&& r) noexcept : p(r.p), ctl(r.ctl) + { + r.p = nullptr; + r.ctl = nullptr; + } + + template + shared_ptr(const shared_ptr& r, T* const p) noexcept : p(p), ctl(r.ctl) + { + if (ctl) + ctl->add_shared(); + } + + template + shared_ptr(shared_ptr&& r, T* const p) noexcept : p(p), ctl(r.ctl) + { + r.p = nullptr; + r.ctl = nullptr; + } + + // TODO(mrdomino): moar ctors + ~shared_ptr() { if (ctl) ctl->release_shared(); } + shared_ptr& operator=(shared_ptr r) noexcept + { + swap(r); + return *this; + } + + void reset() noexcept + { + if (ctl) + ctl->release_shared(); + p = nullptr; + ctl = nullptr; + } + + void reset(auto* const p2) + { + shared_ptr(p2).swap(*this); + } + + void swap(shared_ptr& r) noexcept + { + using std::swap; + swap(p, r.p); + swap(ctl, r.ctl); + } + + element_type* get() const noexcept + { + return p; + } + + // TODO(mrdomino): fix for shared_ptr + T& operator*() const noexcept + { + if (!p) + __builtin_trap(); + return *p; + } + + // TODO(mrdomino): fix for shared_ptr + T* operator->() const noexcept + { + if (!p) + __builtin_trap(); + return *p; + } + + element_type& operator[](ptrdiff_t i) const + { + return *(p + i); + } + + size_t use_count() const noexcept + { + return ctl ? ctl->use_count() : 0; + } + + explicit operator bool() const noexcept + { + return p; + } + + template + bool owner_before(const shared_ptr& r) const noexcept + { + return p < r.p; + } + + // TODO(mrdomino): owner_before(weak_ptr const&) + private: T* p; __::shared_control* ctl; }; +// TODO(mrdomino): non-member functions (make_shared et al) +// TODO(mrdomino): weak_ptr + +// TODO(someday): std::atomic + } // namespace ctl #endif // COSMOPOLITAN_CTL_SHARED_PTR_H_ diff --git a/test/ctl/shared_ptr_test.cc b/test/ctl/shared_ptr_test.cc index c00eab891..41cf41ffa 100644 --- a/test/ctl/shared_ptr_test.cc +++ b/test/ctl/shared_ptr_test.cc @@ -18,9 +18,14 @@ #include "ctl/shared_ptr.h" +// #include +// #define ctl std + template using Ptr = ctl::shared_ptr; +#undef ctl + int main() { @@ -30,6 +35,35 @@ main() { Ptr x(new int()); + if (x.use_count() != 1) + return 1; + Ptr y(x); + if (x.use_count() != 2 || y.use_count() != 2) + return 2; + x.reset(); + if (x.use_count() || y.use_count() != 1) + return 3; } + + { + Ptr x(new int()); + x.reset(new int(2)); + if (x.use_count() != 1) + return 5; + } + + // TODO(mrdomino): +#if 0 + { + Ptr x(new int); + Ptr y(x, nullptr); + if (x.use_count() != 2) + return 7; + } +#endif + + // TODO(mrdomino): exercise more of API + // TODO(mrdomino): threading stress-test + return 0; }