aboutsummaryrefslogblamecommitdiff
path: root/include/salticidae/ref.h
blob: c2dcdd34aa025973c7aa5a2cfc51b9515600df5b (plain) (tree)































                                                                                  










































                                                                    
















































                                                  
           







                                                      
                        

                              


                     

                                            
                                 

     

                                            




















                                                                                  

                                                                             





                                                              



                                                                    


                                                  

                              


                     




                                            


                                             
                                






                                            





                                            






















                                                                    

                             


                         








                                                               

                                                                    
                                        
                             

 
 

















                                                                       
/**
 * Copyright (c) 2018 Cornell University.
 *
 * Author: Ted Yin <tederminant@gmail.com>
 *
 * 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 <atomic>
#include <functional>

namespace salticidae {

template<typename T>
class BoxObj {
    T *obj;

    void release() {
        if (obj) delete obj;
    }

    public:
    template<typename T__, typename T_>
    friend BoxObj<T__> static_pointer_cast(const BoxObj<T_> &other);
    operator T*() const { return obj; }
    T *operator->() const { return obj; }
    BoxObj(): obj(nullptr) {}
    BoxObj(T *obj): obj(obj) {}
    BoxObj &operator=(const BoxObj &other) = delete;
    BoxObj &operator=(BoxObj &&other) {
        release();
        obj = other.obj;
        other.obj = nullptr;
        return *this;
    }

    BoxObj(const BoxObj &other) = delete;
    BoxObj(BoxObj &&other): obj(other.obj) {
        other.obj = nullptr;
    }

    template<typename T_>
    BoxObj(BoxObj<T_> &&other): obj(other.obj) {
        other.obj = nullptr;
    }

    ~BoxObj() { release(); }
};

template<typename T, typename T_>
BoxObj<T> static_pointer_cast(BoxObj<T_> &&other) {
    BoxObj<T> box{};
    box.obj = static_cast<T *>(other.obj);
    return std::move(box);
}

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<typename T, typename R> class RcObjBase;

template<typename T, typename R>
class WeakObjBase {
    T *obj;
    R *ctl;
    void release() { if (ctl) ctl->release_weak(); }
    public:
    friend RcObjBase<T, R>;
    friend std::hash<WeakObjBase<T, R>>;
    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<T, R> &other);

    ~WeakObjBase() { release(); }
};

template<typename T, typename R>
class RcObjBase {
    T *obj;
    R *ctl;
    void release() {
        if (ctl && ctl->release_ref())
            delete obj;
    }
    public:
    friend WeakObjBase<T, R>;
    friend std::hash<RcObjBase<T, R>>;
    template<typename T__, typename T_, typename R_>
    friend RcObjBase<T__, R_> static_pointer_cast(const RcObjBase<T_, R_> &other);
    template<typename T__, typename T_, typename R_>
    friend RcObjBase<T__, R_> static_pointer_cast(RcObjBase<T_, R_> &&other);
    template<typename T_, typename R_> friend class RcObjBase;

    operator T*() const { return obj; }
    T *operator->() const { return<