aboutsummaryrefslogblamecommitdiffstats
path: root/util/generic/ptr.h
blob: cc2e3c0f51907e038610591e008dac326f3238c8 (plain) (tree)
1
2
3
4
5
6
7
8
9
            
 
                

                     
                       
                      
                      
                  
 
                                 
                                 
                                
 

                                                                                       
                                  





                                                                             
                                                           




                                 

             



                                      
 
                 
                      
                                             
     
  

                      
                                               


                         




                                                         
                                                            
                                          



                      
                                               





                              
                                               






                      
                                               





                                                   
                                            



                              
                         
 
                                           

                       


                                       
                                                       


                            
                                                       


                            
                                                    
                                

          
                                    

                                                       
                                                
                   
                    





                                                    
                                          
                              


                              
                                                   
                              










                                                                   
                           
                                                        
                                            


               
                                               


                         
                        

                    
                                                            





                               
                                                             

                                   
                                                             




                        
                                                         

                  
                                    
                       
     
                                            

                         
                                    


                                      


                                                           
        
                                      







                           
                           
                                                      








                                              
                                   


               
                                             


                         
                                                      



                                             


                                           
 
                                                      


                                                 
 

                                                
                       

                    
                                    
                       
     
                                                       

                                   
                                                             




                        
                                                                         
                           
 
                                                         

                  
                                           

                         
                                    

                  
                                               

                         



                                                 


                                                 
 



                                                       
 
                                      


                                                           
        
                                      








                                       
                                                     
                                                          
 




                                           
                                    
                   
                                                 


                           
                                    
 
                                          

                                           
     
 
                                

                                          
     
                                            
                                           
                                   



                                              
                                  
                 
 
                                               

                              
                                   

                                          
     
 


                                   
 
                                        
 

               
 



                                                                                 


                                                                     





                                                                                
                                                                                



                                                                             

                                                          




                                                                                




                                                          
                                           
                    


                 
                                             
                    

                   
 
                                              
                    
 

                    
                                                      
                    



                             
                             
                                                                    



                                    
 


                         
                                                 










                                                     
                             
                
     
                                                         



                  
            
                                                                                                





                                                                                                    
                                                            



                     





                                                       




                                                    
                                                               



                      

                                  
                                                                        
                
     
                                                         

               
                                    

                  
                                                 

                         
                                 
                                           
     
                                                             

                            
                         
         
                   
 
                                           


                                          


                                                           
        
                                



                         
                                  







                           
                             
                                                      




                                                                      
                                                                                                                     
                             
                                                                                    
       
                                                                                                                                 



               
 
                                  
                
 
                                                                   


                  
 




                                                              
                                                          
     
                       
     
 
                                                                      



                  





                                                                 
                                                                         
                      
 
                     
 

                                       
                                                                             
                
     
                                                         

               
                                          
                  
 
                                                      
                         
 
                                 
                                                
     
 


                                           
                                      


                                                           
        
                                
                            
                         
         
     
 
                                  
                            
                           
         
     
 
          

                                    
  
                                                           





                                                                           





                              
                                      

                    
                                        


                      
                                           

                        
                                            
 
                                           

                
                                             


                  
                                                 














                                     
                                                                                        
                             
                                                                                          
 
                                                                               
                                                                   
                                              
 
                                                                               
                                                                             

                                              
                                    

                                                               
 
       
                                













                                         
                                          



               
                                                        
                                        

                


                          
                                                   











                                              
                                                        
                                                             



                  
 







                                                        
                                                         



                      

                                 
                                                                     
                
     
                                                         

               
                                 
                                 
 
                                    

                  
                                                 

                  
                                              


                         
                                           

                                  


                                                                                                             





                                                        




                                                                                                             






                                                        
     
                                      


                                                           


                            
                                      

                         
                                



                      
                                  



                               
                                      










                           
                                    
                                                    




                                                                    
                                                          
                                                                 
                                                          
                                                   
                                                           
                                              
 
                                       
                                                                           
                                                                      
 
                                       
                                                                           
                                                                      
 
                  



                                 
                       
     

                



                                 
                       
     
  
                                    
                                                           
       
                                            

               
 


                                      
 




                                          
                        
                    
 
                                                     
                      
 
                     
 
                                                       
                             
 
                                                             

                        
         
     
 
                                                         

                  
                                    
                       
     
 
                                            
                         
 
                                    
                  
 
                                      


                                                           
        
                                      

                           
 
          
  
                        
                                  
                                                                                           
                                        
 
       
                               









                                 
                                          

                       
                                            

                        
                         



                        
                                         

                                 
                                           

                      
                                                         

                      
                                                

                   
                                      


                                                           
      
        
                           







                                         
                                                                                                            


                  
       
                 

                
                                      











                           
#pragma once

#include "fwd.h"
#include "utility.h"
#include "intrlist.h"
#include "refcount.h"
#include "typetraits.h"
#include "singleton.h"

#include <type_traits>
#include <utility>

#include <util/system/compiler.h>
#include <util/system/defaults.h>
#include <util/system/yassert.h>

template <class T, class U>
using TGuardConversion = typename std::enable_if_t<std::is_convertible<U*, T*>::value>;

template <class T>
inline void AssertTypeComplete() {
    // If compiler triggers this error from destructor of your class with
    // smart pointer, then may be you should move the destructor definition
    // to the .cpp file, where type T have full definition.
    //
    // 'delete' called on pointer to incomplete type is
    // undefined behavior (missing destructor call/corrupted memory manager).
    // 'sizeof' is used to trigger compile-time error.
    static_assert(sizeof(T) != 0, "Type must be complete");
}

template <class T>
inline void CheckedDelete(T* t) {
    AssertTypeComplete<T>();

    delete t;
}

template <class T>
inline void CheckedArrayDelete(T* t) {
    AssertTypeComplete<T>();

    delete[] t;
}

class TNoAction {
public:
    template <class T>
    static inline void Destroy(T*) noexcept {
    }
};

class TDelete {
public:
    template <class T>
    static inline void Destroy(T* t) noexcept {
        CheckedDelete(t);
    }

    /*
     * special handling for nullptr - call nothing
     */
    static inline void Destroy(std::nullptr_t) noexcept {
    }

    /*
     * special handling for void* - call ::operator delete()
     */
    static void Destroy(void* t) noexcept;
};

class TDeleteArray {
public:
    template <class T>
    static inline void Destroy(T* t) noexcept {
        CheckedArrayDelete(t);
    }
};

class TDestructor {
public:
    template <class T>
    static inline void Destroy(T* t) noexcept {
        (void)t;
        t->~T();
    }
};

class TFree {
public:
    template <class T>
    static inline void Destroy(T* t) noexcept {
        DoDestroy((void*)t);
    }

private:
    /*
     * we do not want dependancy on cstdlib here...
     */
    static void DoDestroy(void* t) noexcept;
};

template <class Base, class T>
class TPointerCommon {
public:
    using TValueType = T;

    inline T* operator->() const noexcept {
        T* ptr = AsT();
        Y_ASSERT(ptr);
        return ptr;
    }

#ifndef __cpp_impl_three_way_comparison
    template <class C>
    inline bool operator==(const C& p) const noexcept {
        return (p == AsT());
    }

    template <class C>
    inline bool operator!=(const C& p) const noexcept {
        return (p != AsT());
    }
#endif

    inline explicit operator bool() const noexcept {
        return nullptr != AsT();
    }

protected:
    inline T* AsT() const noexcept {
        return (static_cast<const Base*>(this))->Get();
    }

    static inline T* DoRelease(T*& t) noexcept {
        T* ret = t;
        t = nullptr;
        return ret;
    }
};

template <class Base, class T>
class TPointerBase: public TPointerCommon<Base, T> {
public:
    inline T& operator*() const noexcept {
        Y_ASSERT(this->AsT());

        return *(this->AsT());
    }

    inline T& operator[](size_t n) const noexcept {
        Y_ASSERT(this->AsT());

        return (this->AsT())[n];
    }
};

/*
 * void*-like pointers does not have operator*
 */
template <class Base>
class TPointerBase<Base, void>: public TPointerCommon<Base, void> {
};

template <class T, class D>
class TAutoPtr: public TPointerBase<TAutoPtr<T, D>, T> {
public:
    inline TAutoPtr(T* t = nullptr) noexcept
        : T_(t)
    {
    }

    inline TAutoPtr(const TAutoPtr& t) noexcept
        : T_(t.Release())
    {
    }

    inline ~TAutoPtr() {
        DoDestroy();
    }

    inline TAutoPtr& operator=(const TAutoPtr& t) noexcept {
        if (this != &t) {
            Reset(t.Release());
        }

        return *this;
    }

    inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
        return this->DoRelease(T_);
    }

    Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
        if (T_ != t) {
            DoDestroy();
            T_ = t;
        }
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Destroy();
    }

    inline void Destroy() noexcept {
        Reset(nullptr);
    }

    inline void Swap(TAutoPtr& r) noexcept {
        DoSwap(T_, r.T_);
    }

    inline T* Get() const noexcept {
        return T_;
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void DoDestroy() noexcept {
        if (T_) {
            D::Destroy(T_);
        }
    }

private:
    mutable T* T_;
};

template <class T, class D>
class THolder: public TPointerBase<THolder<T, D>, T> {
public:
    constexpr THolder() noexcept
        : T_(nullptr)
    {
    }

    constexpr THolder(std::nullptr_t) noexcept
        : T_(nullptr)
    {
    }

    explicit THolder(T* t) noexcept
        : T_(t)
    {
    }

    inline THolder(TAutoPtr<T, D> t) noexcept
        : T_(t.Release())
    {
    }

    template <class U, class = TGuardConversion<T, U>>
    inline THolder(TAutoPtr<U, D> t) noexcept
        : T_(t.Release())
    {
    }

    inline THolder(THolder&& that) noexcept
        : T_(that.Release())
    {
    }

    template <class U, class = TGuardConversion<T, U>>
    inline THolder(THolder<U, D>&& that) noexcept
        : T_(that.Release())
    {
    }

    THolder(const THolder&) = delete;
    THolder& operator=(const THolder&) = delete;

    inline ~THolder() {
        DoDestroy();
    }

    inline void Destroy() noexcept {
        Reset(nullptr);
    }

    inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
        return this->DoRelease(T_);
    }

    Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
        if (T_ != t) {
            DoDestroy();
            T_ = t;
        }
    }

    Y_REINITIALIZES_OBJECT inline void Reset(TAutoPtr<T, D> t) noexcept {
        Reset(t.Release());
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Destroy();
    }

    inline void Swap(THolder& r) noexcept {
        DoSwap(T_, r.T_);
    }

    inline T* Get() const noexcept {
        return T_;
    }

    inline operator TAutoPtr<T, D>() noexcept {
        return Release();
    }

    THolder& operator=(std::nullptr_t) noexcept {
        this->Reset(nullptr);
        return *this;
    }

    THolder& operator=(THolder&& that) noexcept {
        this->Reset(that.Release());
        return *this;
    }

    template <class U>
    THolder& operator=(THolder<U, D>&& that) noexcept {
        this->Reset(that.Release());
        return *this;
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void DoDestroy() noexcept {
        if (T_) {
            D::Destroy(T_);
        }
    }

private:
    T* T_;
};

template <typename T, typename... Args>
[[nodiscard]] THolder<T> MakeHolder(Args&&... args) {
    return THolder<T>(new T(std::forward<Args>(args)...));
}

/*
 * usage:
 * class T: public TRefCounted<T>
 * and we get methods Ref() && UnRef() with
 * proper destruction of last UnRef()
 */
template <class T, class C, class D>
class TRefCounted {
public:
    inline TRefCounted(long initval = 0) noexcept
        : Counter_(initval)
    {
    }

    inline ~TRefCounted() = default;

    inline void Ref(intptr_t d) noexcept {
        auto resultCount = Counter_.Add(d);
        Y_ASSERT(resultCount >= d);
        (void)resultCount;
    }

    inline void Ref() noexcept {
        auto resultCount = Counter_.Inc();
        Y_ASSERT(resultCount != 0);
        (void)resultCount;
    }

    inline void UnRef(intptr_t d) noexcept {
        auto resultCount = Counter_.Sub(d);
        Y_ASSERT(resultCount >= 0);
        if (resultCount == 0) {
            D::Destroy(static_cast<T*>(this));
        }
    }

    inline void UnRef() noexcept {
        UnRef(1);
    }

    inline intptr_t RefCount() const noexcept {
        return Counter_.Val();
    }

    inline void DecRef() noexcept {
        auto resultCount = Counter_.Dec();
        Y_ASSERT(resultCount >= 0);
        (void)resultCount;
    }

    TRefCounted(const TRefCounted&)
        : Counter_(0)
    {
    }

    void operator=(const TRefCounted&) {
    }

private:
    C Counter_;
};

/**
 * Atomically reference-counted base with a virtual destructor.
 *
 * @note Plays well with inheritance, should be used for refcounted base classes.
 */
struct TThrRefBase: public TRefCounted<TThrRefBase, TAtomicCounter> {
    virtual ~TThrRefBase();
};

/**
 * Atomically reference-counted base.
 *
 * Deletes refcounted object as type T.
 *
 * @warning Additional care should be taken with regard to inheritance.  If used
 * as a base class, @p T should either declare a virtual destructor, or be
 * derived from @p TThrRefBase instead. Otherwise, only destructor of class @p T
 * would be called, potentially slicing the object and creating memory leaks.
 *
 * @note To avoid accidental inheritance when it is not originally intended,
 * class @p T should be marked as final.
 */
template <class T, class D = TDelete>
using TAtomicRefCount = TRefCounted<T, TAtomicCounter, D>;

/**
 * Non-atomically reference-counted base.
 *
 * @warning Not thread-safe. Use with great care. If in doubt, use @p ThrRefBase
 * or @p TAtomicRefCount instead.
 */
template <class T, class D = TDelete>
using TSimpleRefCount = TRefCounted<T, TSimpleCounter, D>;

template <class T>
class TDefaultIntrusivePtrOps {
public:
    static inline void Ref(T* t) noexcept {
        Y_ASSERT(t);

        t->Ref();
    }

    static inline void UnRef(T* t) noexcept {
        Y_ASSERT(t);

        t->UnRef();
    }

    static inline void DecRef(T* t) noexcept {
        Y_ASSERT(t);

        t->DecRef();
    }

    static inline long RefCount(const T* t) noexcept {
        Y_ASSERT(t);

        return t->RefCount();
    }
};

template <class T, class Ops>
class TIntrusivePtr: public TPointerBase<TIntrusivePtr<T, Ops>, T> {
    template <class U, class O>
    friend class TIntrusivePtr;

    template <class U, class O>
    friend class TIntrusiveConstPtr;

public:
    struct TNoIncrement {
    };

    inline TIntrusivePtr(T* t = nullptr) noexcept
        : T_(t)
    {
        Ops();
        Ref();
    }

    inline TIntrusivePtr(T* t, TNoIncrement) noexcept
        : T_(t)
    {
        Ops();
    }

    inline ~TIntrusivePtr() {
        UnRef();
    }

    inline TIntrusivePtr(const TIntrusivePtr& p) noexcept
        : T_(p.T_)
    {
        Ref();
    }

    // NOTE:
    // without std::enable_if_t compiler sometimes tries to use this constructor inappropriately
    // e.g.
    //     struct A {};
    //     struct B {};
    //     void Func(TIntrusivePtr<A>);
    //     void Func(TIntrusivePtr<B>);
    //     ...
    //     Func(TIntrusivePtr<A>(new A)); // <--- compiler can't decide which version of Func to use
    template <class U, class = TGuardConversion<T, U>>
    inline TIntrusivePtr(const TIntrusivePtr<U>& p) noexcept
        : T_(p.Get())
    {
        Ref();
    }

    template <class U, class = TGuardConversion<T, U>>
    inline TIntrusivePtr(TIntrusivePtr<U>&& p) noexcept
        : T_(p.T_)
    {
        p.T_ = nullptr;
    }

    inline TIntrusivePtr(TIntrusivePtr&& p) noexcept
        : T_(nullptr)
    {
        Swap(p);
    }

    inline TIntrusivePtr& operator=(TIntrusivePtr p) noexcept {
        p.Swap(*this);

        return *this;
    }

    // Effectively replace both:
    // Reset(const TIntrusivePtr&)
    // Reset(TIntrusivePtr&&)
    Y_REINITIALIZES_OBJECT inline void Reset(TIntrusivePtr t) noexcept {
        Swap(t);
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Drop();
    }

    inline T* Get() const noexcept {
        return T_;
    }

    inline void Swap(TIntrusivePtr& r) noexcept {
        DoSwap(T_, r.T_);
    }

    inline void Drop() noexcept {
        TIntrusivePtr(nullptr).Swap(*this);
    }

    inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
        T* res = T_;
        if (T_) {
            Ops::DecRef(T_);
            T_ = nullptr;
        }
        return res;
    }

    inline long RefCount() const noexcept {
        return T_ ? Ops::RefCount(T_) : 0;
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void Ref() noexcept {
        if (T_) {
            Ops::Ref(T_);
        }
    }

    inline void UnRef() noexcept {
        if (T_) {
            Ops::UnRef(T_);
        }
    }

private:
    mutable T* T_;
};

template <class T, class Ops>
struct THash<TIntrusivePtr<T, Ops>>: THash<const T*> {
    using THash<const T*>::operator();
    inline size_t operator()(const TIntrusivePtr<T, Ops>& ptr) const {
        return THash<const T*>::operator()(ptr.Get());
    }
};

// Behaves like TIntrusivePtr but returns const T* to prevent user from accidentally modifying the referenced object.
template <class T, class Ops>
class TIntrusiveConstPtr: public TPointerBase<TIntrusiveConstPtr<T, Ops>, const T> {
public:
    inline TIntrusiveConstPtr(T* t = nullptr) noexcept // we need a non-const pointer to Ref(), UnRef() and eventually delete it.
        : T_(t)
    {
        Ops();
        Ref();
    }

    inline ~TIntrusiveConstPtr() {
        UnRef();
    }

    inline TIntrusiveConstPtr(const TIntrusiveConstPtr& p) noexcept
        : T_(p.T_)
    {
        Ref();
    }

    inline TIntrusiveConstPtr(TIntrusiveConstPtr&& p) noexcept
        : T_(nullptr)
    {
        Swap(p);
    }

    inline TIntrusiveConstPtr(TIntrusivePtr<T> p) noexcept
        : T_(p.T_)
    {
        p.T_ = nullptr;
    }

    template <class U, class = TGuardConversion<T, U>>
    inline TIntrusiveConstPtr(const TIntrusiveConstPtr<U>& p) noexcept
        : T_(p.T_)
    {
        Ref();
    }

    template <class U, class = TGuardConversion<T, U>>
    inline TIntrusiveConstPtr(TIntrusiveConstPtr<U>&& p) noexcept
        : T_(p.T_)
    {
        p.T_ = nullptr;
    }

    inline TIntrusiveConstPtr& operator=(TIntrusiveConstPtr p) noexcept {
        p.Swap(*this);

        return *this;
    }

    // Effectively replace both:
    // Reset(const TIntrusiveConstPtr&)
    // Reset(TIntrusiveConstPtr&&)
    Y_REINITIALIZES_OBJECT inline void Reset(TIntrusiveConstPtr t) noexcept {
        Swap(t);
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Drop();
    }

    inline const T* Get() const noexcept {
        return T_;
    }

    inline void Swap(TIntrusiveConstPtr& r) noexcept {
        DoSwap(T_, r.T_);
    }

    inline void Drop() noexcept {
        TIntrusiveConstPtr(nullptr).Swap(*this);
    }

    inline long RefCount() const noexcept {
        return T_ ? Ops::RefCount(T_) : 0;
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void Ref() noexcept {
        if (T_ != nullptr) {
            Ops::Ref(T_);
        }
    }

    inline void UnRef() noexcept {
        if (T_ != nullptr) {
            Ops::UnRef(T_);
        }
    }

private:
    T* T_;

    template <class U, class O>
    friend class TIntrusiveConstPtr;
};

template <class T, class Ops>
struct THash<TIntrusiveConstPtr<T, Ops>>: THash<const T*> {
    using THash<const T*>::operator();
    inline size_t operator()(const TIntrusiveConstPtr<T, Ops>& ptr) const {
        return THash<const T*>::operator()(ptr.Get());
    }
};

template <class T, class Ops>
class TSimpleIntrusiveOps {
    using TFunc = void (*)(T*)
#if __cplusplus >= 201703
        noexcept
#endif
        ;

    static void DoRef(T* t) noexcept {
        Ops::Ref(t);
    }

    static void DoUnRef(T* t) noexcept {
        Ops::UnRef(t);
    }

public:
    inline TSimpleIntrusiveOps() noexcept {
        InitStaticOps();
    }

    inline ~TSimpleIntrusiveOps() = default;

    static inline void Ref(T* t) noexcept {
        Ref_(t);
    }

    static inline void UnRef(T* t) noexcept {
        UnRef_(t);
    }

private:
    static inline void InitStaticOps() noexcept {
        struct TInit {
            inline TInit() noexcept {
                Ref_ = DoRef;
                UnRef_ = DoUnRef;
            }
        };

        Singleton<TInit>();
    }

private:
    static TFunc Ref_;
    static TFunc UnRef_;
};

template <class T, class Ops>
typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::Ref_ = nullptr;

template <class T, class Ops>
typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::UnRef_ = nullptr;

template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
[[nodiscard]] TIntrusivePtr<T, Ops> MakeIntrusive(Args&&... args) {
    return new T{std::forward<Args>(args)...};
}

template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
[[nodiscard]] TIntrusiveConstPtr<T, Ops> MakeIntrusiveConst(Args&&... args) {
    return new T{std::forward<Args>(args)...};
}

template <class T, class C, class D>
class TSharedPtr: public TPointerBase<TSharedPtr<T, C, D>, T> {
    template <class TT, class CC, class DD>
    friend class TSharedPtr;

public:
    inline TSharedPtr() noexcept
        : T_(nullptr)
        , C_(nullptr)
    {
    }

    inline TSharedPtr(T* t) {
        THolder<T, D> h(t);

        Init(h);
    }

    inline TSharedPtr(TAutoPtr<T, D> t) {
        Init(t);
    }

    inline TSharedPtr(T* t, C* c) noexcept
        : T_(t)
        , C_(c)
    {
    }

    template <class TT, class = TGuardConversion<T, TT>>
    inline TSharedPtr(THolder<TT>&& t) {
        Init(t);
    }

    inline ~TSharedPtr() {
        UnRef();
    }

    inline TSharedPtr(const TSharedPtr& t) noexcept
        : T_(t.T_)
        , C_(t.C_)
    {
        Ref();
    }

    inline TSharedPtr(TSharedPtr&& t) noexcept
        : T_(nullptr)
        , C_(nullptr)
    {
        Swap(t);
    }

    template <class TT, class = TGuardConversion<T, TT>>
    inline TSharedPtr(const TSharedPtr<TT, C, D>& t) noexcept
        : T_(t.T_)
        , C_(t.C_)
    {
        Ref();
    }

    template <class TT, class = TGuardConversion<T, TT>>
    inline TSharedPtr(TSharedPtr<TT, C, D>&& t) noexcept
        : T_(t.T_)
        , C_(t.C_)
    {
        t.T_ = nullptr;
        t.C_ = nullptr;
    }

    inline TSharedPtr& operator=(TSharedPtr t) noexcept {
        t.Swap(*this);

        return *this;
    }

    // Effectively replace both:
    // Reset(const TSharedPtr& t)
    // Reset(TSharedPtr&& t)
    Y_REINITIALIZES_OBJECT inline void Reset(TSharedPtr t) noexcept {
        Swap(t);
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Drop();
    }

    inline void Drop() noexcept {
        TSharedPtr().Swap(*this);
    }

    inline T* Get() const noexcept {
        return T_;
    }

    inline C* ReferenceCounter() const noexcept {
        return C_;
    }

    inline void Swap(TSharedPtr& r) noexcept {
        DoSwap(T_, r.T_);
        DoSwap(C_, r.C_);
    }

    inline long RefCount() const noexcept {
        return C_ ? C_->Val() : 0;
    }

    template <class TT>
    [[nodiscard]] inline TSharedPtr<TT, C, D> As() & noexcept {
        static_assert(std::has_virtual_destructor<TT>(), "Type should have a virtual dtor");
        static_assert(std::is_base_of<T, TT>(), "When downcasting from T to TT, T should be a parent of TT");
        if (const auto ttPtr = dynamic_cast<TT*>(T_)) {
            TSharedPtr<TT, C, D> ttSharedPtr(ttPtr, C_);
            ttSharedPtr.Ref();
            return ttSharedPtr;
        } else {
            return TSharedPtr<TT, C, D>{};
        }
    }

    template <class TT>
    [[nodiscard]] inline TSharedPtr<TT, C, D> As() && noexcept {
        static_assert(std::has_virtual_destructor<TT>(), "Type should have a virtual dtor");
        static_assert(std::is_base_of<T, TT>(), "When downcasting from T to TT, T should be a parent of TT");
        if (const auto ttPtr = dynamic_cast<TT*>(T_)) {
            TSharedPtr<TT, C, D> ttSharedPtr(ttPtr, C_);
            T_ = nullptr;
            C_ = nullptr;
            return ttSharedPtr;
        } else {
            return TSharedPtr<TT, C, D>{};
        }
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    template <class X>
    inline void Init(X& t) {
        C_ = !!t ? new C(1) : nullptr;
        T_ = t.Release();
    }

    inline void Ref() noexcept {
        if (C_) {
            C_->Inc();
        }
    }

    inline void UnRef() noexcept {
        if (C_ && !C_->Dec()) {
            DoDestroy();
        }
    }

    inline void DoDestroy() noexcept {
        if (T_) {
            D::Destroy(T_);
        }

        delete C_;
    }

private:
    T* T_;
    C* C_;
};

template <class T, class C, class D>
struct THash<TSharedPtr<T, C, D>>: THash<const T*> {
    using THash<const T*>::operator();
    inline size_t operator()(const TSharedPtr<T, C, D>& ptr) const {
        return THash<const T*>::operator()(ptr.Get());
    }
};

template <class T, class D = TDelete>
using TAtomicSharedPtr = TSharedPtr<T, TAtomicCounter, D>;

// use with great care. if in doubt, use TAtomicSharedPtr instead
template <class T, class D = TDelete>
using TSimpleSharedPtr = TSharedPtr<T, TSimpleCounter, D>;

template <typename T, typename C, typename... Args>
[[nodiscard]] TSharedPtr<T, C> MakeShared(Args&&... args) {
    return new T{std::forward<Args>(args)...};
}

template <typename T, typename... Args>
[[nodiscard]] inline TAtomicSharedPtr<T> MakeAtomicShared(Args&&... args) {
    return MakeShared<T, TAtomicCounter>(std::forward<Args>(args)...);
}

template <typename T, typename... Args>
[[nodiscard]] inline TSimpleSharedPtr<T> MakeSimpleShared(Args&&... args) {
    return MakeShared<T, TSimpleCounter>(std::forward<Args>(args)...);
}

class TCopyClone {
public:
    template <class T>
    static inline T* Copy(T* t) {
        if (t)
            return t->Clone();
        return nullptr;
    }
};

class TCopyNew {
public:
    template <class T>
    static inline T* Copy(T* t) {
        if (t)
            return new T(*t);
        return nullptr;
    }
};

template <class T, class C, class D>
class TCopyPtr: public TPointerBase<TCopyPtr<T, C, D>, T> {
public:
    inline TCopyPtr(T* t = nullptr) noexcept
        : T_(t)
    {
    }

    inline TCopyPtr(const TCopyPtr& t)
        : T_(C::Copy(t.Get()))
    {
    }

    inline TCopyPtr(TCopyPtr&& t) noexcept
        : T_(nullptr)
    {
        Swap(t);
    }

    inline ~TCopyPtr() {
        DoDestroy();
    }

    inline TCopyPtr& operator=(TCopyPtr t) noexcept {
        t.Swap(*this);

        return *this;
    }

    inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
        return DoRelease(T_);
    }

    Y_REINITIALIZES_OBJECT inline void Reset(T* t) noexcept {
        if (T_ != t) {
            DoDestroy();
            T_ = t;
        }
    }

    Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
        Destroy();
    }

    inline void Destroy() noexcept {
        Reset(nullptr);
    }

    inline void Swap(TCopyPtr& r) noexcept {
        DoSwap(T_, r.T_);
    }

    inline T* Get() const noexcept {
        return T_;
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void DoDestroy() noexcept {
        if (T_)
            D::Destroy(T_);
    }

private:
    T* T_;
};

// Copy-on-write pointer
template <class TPtr, class TCopy>
class TCowPtr: public TPointerBase<TCowPtr<TPtr, TCopy>, const typename TPtr::TValueType> {
    using T = typename TPtr::TValueType;

public:
    inline TCowPtr() = default;

    inline TCowPtr(const TPtr& p)
        : T_(p)
    {
    }

    inline TCowPtr(T* p)
        : T_(p)
    {
    }

    inline const T* Get() const noexcept {
        return Const();
    }

    inline const T* Const() const noexcept {
        return T_.Get();
    }

    inline T* Mutable() {
        Unshare();

        return T_.Get();
    }

    inline bool Shared() const noexcept {
        return T_.RefCount() > 1;
    }

    inline void Swap(TCowPtr& r) noexcept {
        T_.Swap(r.T_);
    }

    Y_REINITIALIZES_OBJECT inline void Reset(TCowPtr p) {
        p.Swap(*this);
    }

    Y_REINITIALIZES_OBJECT inline void Reset() {
        T_.Reset();
    }

#ifdef __cpp_impl_three_way_comparison
    template <class Other>
    inline bool operator==(const Other& p) const noexcept {
        return (p == Get());
    }
#endif
private:
    inline void Unshare() {
        if (Shared()) {
            Reset(TCopy::Copy(T_.Get()));
        }
    }

private:
    TPtr T_;
};

// saves .Get() on argument passing. Intended usage: Func(TPtrArg<X> p); ... TIntrusivePtr<X> p2;  Func(p2);
template <class T>
class TPtrArg {
    T* Ptr;

public:
    TPtrArg(T* p)
        : Ptr(p)
    {
    }
    TPtrArg(const TIntrusivePtr<T>& p)
        : Ptr(p.Get())
    {
    }
    operator T*() const {
        return Ptr;
    }
    T* operator->() const {
        return Ptr;
    }
    T* Get() const {
        return Ptr;
    }
};