/** * 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 { T *obj; R *ctl; void release() { if (ctl) ctl->release_weak(); } public: friend RcObjBase; friend std::hash>; WeakObjBase(): ctl(nullptr) {} WeakObjBase &operator=(const WeakObjBase &other) { release(); obj = other.obj; if ((ctl = other.ctl)) ctl->add_weak(); return *this; } WeakObjBase(const WeakObjBase &other): obj(other.obj), ctl(other.ctl) { if (ctl) ctl->add_weak(); } WeakObjBase(WeakObjBase &&other): obj(other.obj), 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; if ((ctl = other.ctl)) ctl->add_ref(); return *this; } template RcObjBase(const RcObjBase &other): obj(other.obj), ctl(other.ctl) { if (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); if ((rc.ctl = other.ctl)) rc.ctl->add_ref(); return std::move(rc); } template inline WeakObjBase::WeakObjBase(const RcObjBase &other): obj(other.obj), ctl(other.ctl) { if (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