aboutsummaryrefslogblamecommitdiffstats
path: root/util/generic/refcount.h
blob: 966e853b77fba3ed320e7326f09a1d03ee3b4686 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
            

                               
                                 
                                
 

                                                          
 
       
                                                            


                           
                                      

                
                                                    
                
                             
     
 
                                       
     
 
                                                    


                             
                                       

                      
                                       



                         
                                

                    
                                             


                        
                         






                               
                                        
 
                                   
 



                                           
 
                               
                                                                                           
     
 

                    
     
                                    
      
 
                                                                                                                 
                                                            
                                                                                                                           
                                                                      
 
                                                                    
                                                                                         

                 
                                                                                         


                 
                      
                                                    


                           
                                       
 
                                                    
     
 
                                       
     
                                                    
                                      
 
                                       

                      
                                             

                                   
                                       






                                             
                                    





                                                           



                     
                                       
                                                            
                 
 
                                                            

                 
#pragma once

#include <util/system/guard.h>
#include <util/system/atomic.h>
#include <util/system/defaults.h>
#include <util/system/yassert.h>

template <class TCounterCheckPolicy>
class TSimpleCounterTemplate: public TCounterCheckPolicy {
    using TCounterCheckPolicy::Check;

public:
    inline TSimpleCounterTemplate(long initial = 0) noexcept
        : Counter_(initial)
    {
    }

    inline ~TSimpleCounterTemplate() {
        Check();
    }

    inline TAtomicBase Add(TAtomicBase d) noexcept {
        Check();
        return Counter_ += d;
    }

    inline TAtomicBase Inc() noexcept {
        return Add(1);
    }

    inline TAtomicBase Sub(TAtomicBase d) noexcept {
        Check();
        return Counter_ -= d;
    }

    inline TAtomicBase Dec() noexcept {
        return Sub(1);
    }

    inline bool TryWeakInc() noexcept {
        if (!Counter_) {
            return false;
        }

        Inc();
        Y_ASSERT(Counter_ != 0);

        return true;
    }

    inline TAtomicBase Val() const noexcept {
        return Counter_;
    }

private:
    TAtomicBase Counter_;
};

class TNoCheckPolicy {
protected:
    inline void Check() const {
    }
};

#if defined(SIMPLE_COUNTER_THREAD_CHECK)

    #include <util/system/thread.i>

class TCheckPolicy {
public:
    inline TCheckPolicy() {
        ThreadId = SystemCurrentThreadId();
    }

protected:
    inline void Check() const {
        Y_VERIFY(ThreadId == SystemCurrentThreadId(), "incorrect usage of TSimpleCounter");
    }

private:
    size_t ThreadId;
};
#else
using TCheckPolicy = TNoCheckPolicy;
#endif

// Use this one if access from multiple threads to your pointer is an error and you want to enforce thread checks
using TSimpleCounter = TSimpleCounterTemplate<TCheckPolicy>;
// Use this one if you do want to share the pointer between threads, omit thread checks and do the synchronization yourself
using TExplicitSimpleCounter = TSimpleCounterTemplate<TNoCheckPolicy>;

template <class TCounterCheckPolicy>
struct TCommonLockOps<TSimpleCounterTemplate<TCounterCheckPolicy>> {
    static inline void Acquire(TSimpleCounterTemplate<TCounterCheckPolicy>* t) noexcept {
        t->Inc();
    }

    static inline void Release(TSimpleCounterTemplate<TCounterCheckPolicy>* t) noexcept {
        t->Dec();
    }
};

class TAtomicCounter {
public:
    inline TAtomicCounter(long initial = 0) noexcept
        : Counter_(initial)
    {
    }

    inline ~TAtomicCounter() = default;

    inline TAtomicBase Add(TAtomicBase d) noexcept {
        return AtomicAdd(Counter_, d);
    }

    inline TAtomicBase Inc() noexcept {
        return Add(1);
    }

    inline TAtomicBase Sub(TAtomicBase d) noexcept {
        return AtomicSub(Counter_, d);
    }

    inline TAtomicBase Dec() noexcept {
        return Sub(1);
    }

    inline TAtomicBase Val() const noexcept {
        return AtomicGet(Counter_);
    }

    inline bool TryWeakInc() noexcept {
        while (true) {
            intptr_t curValue = Counter_;

            if (!curValue) {
                return false;
            }

            intptr_t newValue = curValue + 1;
            Y_ASSERT(newValue != 0);

            if (AtomicCas(&Counter_, newValue, curValue)) {
                return true;
            }
        }
    }

private:
    TAtomic Counter_;
};

template <>
struct TCommonLockOps<TAtomicCounter> {
    static inline void Acquire(TAtomicCounter* t) noexcept {
        t->Inc();
    }

    static inline void Release(TAtomicCounter* t) noexcept {
        t->Dec();
    }
};