From 5c3b39340d365f5ff37a79424956591e87b44816 Mon Sep 17 00:00:00 2001 From: Determinant Date: Tue, 26 Jun 2018 12:58:54 -0400 Subject: init --- include/salticidae/ref.h | 202 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 include/salticidae/ref.h (limited to 'include/salticidae/ref.h') diff --git a/include/salticidae/ref.h b/include/salticidae/ref.h new file mode 100644 index 0000000..5f54da2 --- /dev/null +++ b/include/salticidae/ref.h @@ -0,0 +1,202 @@ +/** + * Copyright (c) 2018 Cornell University. + * + * Author: Ted Yin + * + * 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 _SALTICIDAE_REF_H +#define _SALTICIDAE_REF_H + +#include +#include + +namespace salticidae { + +struct _RCCtl { + size_t ref_cnt; + size_t weak_cnt; + void add_ref() { ref_cnt++; } + void add_weak() { weak_cnt++; } + bool release_ref() { + if (--ref_cnt) return false; + if (weak_cnt) return true; + delete this; + return true; + } + void release_weak() { + if (--weak_cnt) return; + if (ref_cnt) return; + delete this; + } + size_t get_cnt() { return ref_cnt; } + _RCCtl(): ref_cnt(1), weak_cnt(0) {} + ~_RCCtl() {} +}; + +struct _ARCCtl { + std::atomic_size_t ref_cnt; + std::atomic_size_t weak_cnt; + std::atomic_uint8_t dcnt; + void add_ref() { ref_cnt++; } + void add_weak() { weak_cnt++; } + bool release_ref() { + dcnt++; + if (--ref_cnt) { dcnt--; return false; } + if (weak_cnt) { dcnt--; return true; } + if (!--dcnt) delete this; + return true; + } + void release_weak() { + dcnt++; + if (--weak_cnt) { dcnt--; return; } + if (ref_cnt) { dcnt--; return; } + if (!--dcnt) delete this; + } + size_t get_cnt() { return ref_cnt.load(); } + _ARCCtl(): ref_cnt(1), weak_cnt(0), dcnt(0) {} + ~_ARCCtl() {} +}; + +template class RcObjBase; + +template +class WeakObjBase { + R *ctl; + void release() { if (ctl) ctl->release_weak(); } + public: + friend RcObjBase; + friend std::hash>; + WeakObjBase(): ctl(nullptr) {} + WeakObjBase &operator=(const WeakObjBase &other) { + release(); + ctl = other.ctl; + ctl->add_weak(); + return *this; + } + + WeakObjBase(const WeakObjBase &other): ctl(other.ctl) { + ctl->add_weak(); + } + + WeakObjBase(WeakObjBase &&other): ctl(other.ctl) { + other.ctl = nullptr; + } + + WeakObjBase(const RcObjBase &other); + + ~WeakObjBase() { release(); } +}; + +template +class RcObjBase { + T *obj; + R *ctl; + void release() { + if (ctl && ctl->release_ref()) + delete obj; + } + public: + friend WeakObjBase; + friend std::hash>; + template + friend RcObjBase static_pointer_cast(const RcObjBase &other); + template friend class RcObjBase; + + operator T*() const { return obj; } + T *operator->() const { return obj; } + RcObjBase(): obj(nullptr), ctl(nullptr) {} + RcObjBase(T *obj): obj(obj), ctl(new R()) {} + RcObjBase &operator=(const RcObjBase &other) { + release(); + obj = other.obj; + ctl = other.ctl; + ctl->add_ref(); + return *this; + } + + RcObjBase(const RcObjBase &other): + obj(other.obj), ctl(other.ctl) { + ctl->add_ref(); + } + + template + RcObjBase(const RcObjBase &other): + obj(other.obj), ctl(other.ctl) { + ctl->add_ref(); + } + + RcObjBase(RcObjBase &&other): + obj(other.obj), ctl(other.ctl) { + other.ctl = nullptr; + } + + RcObjBase(const WeakObjBase &other) { + if (other.ctl && other.ctl->ref_cnt) + { + obj = other.obj; + ctl = other.ctl; + ctl->add_ref(); + } + else + { + obj = nullptr; + ctl = nullptr; + } + } + + ~RcObjBase() { release(); } + + size_t get_cnt() const { return ctl ? ctl->get_cnt() : 0; } +}; + +template +RcObjBase static_pointer_cast(const RcObjBase &other) { + RcObjBase rc{}; + rc.obj = static_cast(other.obj); + rc.ctl = other.ctl; + rc.ctl->add_ref(); + return std::move(rc); +} + +template +inline WeakObjBase::WeakObjBase(const RcObjBase &other): + ctl(other.ctl) { + ctl->add_weak(); +} + +template using RcObj = RcObjBase; +template using WeakObj = WeakObjBase; + +template using ArcObj = RcObjBase; +template using AweakObj = WeakObjBase; + +} + +namespace std { + template + struct hash> { + size_t operator()(const salticidae::RcObjBase &k) const { + return (size_t)k.obj; + } + }; +} + +#endif -- cgit v1.2.3