mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 08:20:28 +00:00
wip Implement ctl::shared_ptr
This code does not segfault and it compiles cleanly, and it took a while to get here.
This commit is contained in:
parent
a795017416
commit
b16cf2ee97
3 changed files with 239 additions and 0 deletions
97
ctl/shared_ptr.cc
Normal file
97
ctl/shared_ptr.cc
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||||
|
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||||
|
//
|
||||||
|
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
// any purpose with or without fee is hereby granted, provided that the
|
||||||
|
// above copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#include "shared_ptr.h"
|
||||||
|
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline void
|
||||||
|
incref(_Atomic(size_t)* r)
|
||||||
|
{
|
||||||
|
size_t r2 = atomic_fetch_add_explicit(r, 1, memory_order_relaxed);
|
||||||
|
if (r2 > ((size_t)-1) >> 1)
|
||||||
|
__builtin_trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
decref(_Atomic(size_t)* r)
|
||||||
|
{
|
||||||
|
if (!atomic_fetch_sub_explicit(r, 1, memory_order_release)) {
|
||||||
|
atomic_thread_fence(memory_order_acquire);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t
|
||||||
|
getref(const _Atomic(size_t)* r)
|
||||||
|
{
|
||||||
|
return atomic_load_explicit(r, memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace ctl {
|
||||||
|
|
||||||
|
namespace __ {
|
||||||
|
|
||||||
|
void
|
||||||
|
shared_control::add_shared() noexcept
|
||||||
|
{
|
||||||
|
incref(&shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shared_control::release_shared() noexcept
|
||||||
|
{
|
||||||
|
if (decref(&shared)) {
|
||||||
|
on_zero_shared();
|
||||||
|
release_weak();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shared_control::add_weak() noexcept
|
||||||
|
{
|
||||||
|
incref(&weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shared_control::release_weak() noexcept
|
||||||
|
{
|
||||||
|
if (decref(&weak))
|
||||||
|
on_zero_weak();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
shared_control::use_count() const noexcept
|
||||||
|
{
|
||||||
|
return 1 + getref(&shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
shared_control::weak_count() const noexcept
|
||||||
|
{
|
||||||
|
return getref(&weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __
|
||||||
|
|
||||||
|
} // namespace ctl
|
107
ctl/shared_ptr.h
Normal file
107
ctl/shared_ptr.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||||
|
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||||
|
#ifndef COSMOPOLITAN_CTL_SHARED_PTR_H_
|
||||||
|
#define COSMOPOLITAN_CTL_SHARED_PTR_H_
|
||||||
|
#include "unique_ptr.h"
|
||||||
|
|
||||||
|
namespace ctl {
|
||||||
|
|
||||||
|
// TODO(mrdomino): move
|
||||||
|
struct exception
|
||||||
|
{
|
||||||
|
virtual const char* what() const noexcept
|
||||||
|
{
|
||||||
|
return "exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace __ {
|
||||||
|
|
||||||
|
struct shared_control
|
||||||
|
{
|
||||||
|
_Atomic(size_t) shared;
|
||||||
|
_Atomic(size_t) weak;
|
||||||
|
|
||||||
|
constexpr shared_control() noexcept : shared(0), weak(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~shared_control()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void add_shared() noexcept;
|
||||||
|
void release_shared() noexcept;
|
||||||
|
void add_weak() noexcept;
|
||||||
|
void release_weak() noexcept;
|
||||||
|
size_t use_count() const noexcept;
|
||||||
|
size_t weak_count() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void on_zero_shared() noexcept = 0;
|
||||||
|
virtual void on_zero_weak() noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct shared_pointer : shared_control
|
||||||
|
{
|
||||||
|
T* p;
|
||||||
|
|
||||||
|
static shared_pointer* make(T* p)
|
||||||
|
{
|
||||||
|
return new shared_pointer(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
shared_pointer(T* p) noexcept : p(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_zero_shared() noexcept override
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_zero_weak() noexcept override
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace __
|
||||||
|
|
||||||
|
struct bad_weak_ptr : ctl::exception
|
||||||
|
{
|
||||||
|
const char* what() const noexcept override
|
||||||
|
{
|
||||||
|
return "bad_weak_ptr";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class shared_ptr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr shared_ptr(nullptr_t = nullptr) noexcept
|
||||||
|
: p(nullptr), ctl(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
shared_ptr(T* const p2)
|
||||||
|
{
|
||||||
|
auto hold = ctl::unique_ptr(p2);
|
||||||
|
ctl = __::shared_pointer<T>::make(p2);
|
||||||
|
p = hold.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
~shared_ptr()
|
||||||
|
{
|
||||||
|
if (ctl)
|
||||||
|
ctl->release_shared();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* p;
|
||||||
|
__::shared_control* ctl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ctl
|
||||||
|
|
||||||
|
#endif // COSMOPOLITAN_CTL_SHARED_PTR_H_
|
35
test/ctl/shared_ptr_test.cc
Normal file
35
test/ctl/shared_ptr_test.cc
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||||
|
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||||
|
//
|
||||||
|
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
// any purpose with or without fee is hereby granted, provided that the
|
||||||
|
// above copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#include "ctl/shared_ptr.h"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using Ptr = ctl::shared_ptr<T>;
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Ptr<int> x;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Ptr<int> x(new int());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue