⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 variant.h

📁 Modern C++ Design 一书中实现的程序库
💻 H
📖 第 1 页 / 共 2 页
字号:
        typedef char RawBuffer_t[sizeof(T)];
        enum ObjectState_e { eNone, ePreConstruct, ePostConstruct };

        T               &obj_;
        ObjectState_e   eObjState_;
        RawBuffer_t     bufferOrg_;
        RawBuffer_t     bufferNew_;

    private:
        void SetObj(const RawBuffer_t &buf) throw()
        {
            memcpy(&reinterpret_cast<char &>(obj_), buf, sizeof(buf));
        }    

        void GetObj(RawBuffer_t &buf) throw()
        {
            memcpy(buf, &reinterpret_cast<const char &>(obj_), sizeof(buf));
        }    

    public:
        explicit RawDataKeeper(T &obj) 
            : obj_(obj), eObjState_(eNone)
        {}
    
        // add const U & version ?
        template<typename U>
        void ConstructNew(U &src)
        {
            assert(eObjState_ == eNone);

            GetObj(bufferOrg_);
            
            eObjState_ = ePreConstruct;
            new (&obj_) T(src);
            eObjState_ = ePostConstruct;

            GetObj(bufferNew_);
            SetObj(bufferOrg_);
        }

        void SetNew() throw()
        {
            assert(eObjState_ == ePostConstruct);

            obj_.~T();
            SetObj(bufferNew_);
            eObjState_ = eNone;
        }

        ~RawDataKeeper()
        {
            switch(eObjState_)
            {
            case ePostConstruct:
                SetObj(bufferNew_);
                obj_.~T();
                // fall
            
            case ePreConstruct:
                SetObj(bufferOrg_);
                // fall

            case eNone:
                break;
            }
        }

    private:
        RawDataKeeper(const RawDataKeeper &);
        RawDataKeeper& operator=(const RawDataKeeper &);
    };

    //
    // based on Eric Fridman's safe_swap from boost Variant 
    //
    //   strong exception-safety guarantee.
    //
    // !WARNING!
    //   SafeSwap CANNOT be safely used in the general case if either
    //   argument's data members may be accessed concurrently.
    //
    template<typename T>
    void SafeSwap(T &lhs, T &rhs)
    {
        typedef RawDataKeeper<T> RhsDataKeeper;
        typedef RawDataKeeper<T> LhsDataKeeper;

        RhsDataKeeper rhsKeeper(rhs);
        rhsKeeper.ConstructNew(lhs);
            
        LhsDataKeeper lhsKeeper(lhs);
        lhsKeeper.ConstructNew(rhs);
    
        rhsKeeper.SetNew();
        lhsKeeper.SetNew();
    }


    //
    // based on Eric Fridman's safe_assign from boost Variant 
    //
    //   strong exception-safety guarantee.
    //
    // !WARNING!
    //   SafeAssign CANNOT be safely used in the general case if either
    //   argument's data members may be accessed concurrently.
    //
    template<typename T, typename U>
    void SafeAssign(T &lhs, const U &src)
    {
        typedef RawDataKeeper<T> LhsDataKeeper;

        LhsDataKeeper lhsKeeper(lhs);
        lhsKeeper.ConstructNew(src);
        lhsKeeper.SetNew();
    }

    template<typename T>
    inline void SwapHelper(T &lhs, T &rhs)
    {
        using namespace std;
        swap(lhs, rhs);
    }
} // namespace Private 

////////////////////////////////////////////////////////////////////////////////
// class template Variant
// Implements a discriminated union in C++
////////////////////////////////////////////////////////////////////////////////

template <class TList, class AlignedPODType = AlignedPOD<TList> >
class Variant
{
    // VC7: fatal error C1067: compiler limit :
    // debug information module size exceeded
    // Therfore define this type here 
    typedef typename AlignedPODType::Result Align;

public:
    typedef TList Types;

    // Default constructor
    // Initializes the Variant with a default-constructed object of the 
    // first type in the typelist
    Variant()
    {
        typedef typename TList::Head T;
        new(&buffer_[0]) T;
        vptr_ = VTableImpl<T>::GetVPTR();
    }

    // Copy constructor
    Variant(const Variant& rhs)
    {
        (rhs.vptr_->clone_)(rhs, *this);
    }

private:
    // Converting constructor; accepts any type in the typelist
    // @@@ Suggested simple improvement: accept any type convertible to one of 
    // the types in the typelist. Use Loki::Conversion as a building block
    template <class T>
    void VariantConstruct(const T& val, double)
    {
        STATIC_CHECK((::Loki::TL::IndexOf<TList, T>::value >= 0), 
            Invalid_Type_Used_As_Initializer);
        
        new(&buffer_[0]) T(val);
        vptr_ = VTableImpl<T>::GetVPTR();
    }
    
    // Inter-Variant conversion constructor
    // Current policy is: conversion succeeds iff the actual type of the source 
    // is one of the types accepted by the target
    // @@@ Possible change: accept if the actual type of the source is
    //     convertible to one of the types accepted by the target. Problem to 
    //     solve: handle ambiguities in a satisfactory manner. Suggestion: when
    //     in doubt, do closest to what the compiler would do.
    template <class TList2, typename Align2>
    void VariantConstruct(const Variant<TList2, Align2>& rhs, int)
    {
        typename Converter<Variant<TList2, Align2>, Variant>::Visitor v(*this);
        typename Variant<TList2, Align2>::ConstStrictVisitor& visitor = v;
        rhs.Accept(visitor);
    }

public:
    // VC7 don't support partial ordering
    // The constructor initialization section 
    // is empty which make it to use function instead
    // without the int = 0 the explicit seems to confuse
    // VC7 when the copy constructor should be selected
    // Crazy stuff
    template <class T>
    explicit Variant(const T& val, int = 0)
    {
        VariantConstruct(val, int(0));
    }

    // Canonic assignment operator
    Variant& operator=(const Variant& rhs)
    {
        Private::SafeAssign(*this, rhs);
        return *this;
    }
    
private:
    // Assignment operator from one of the allowed types
    // This is necessary because the constructor is explicit
    template <class T> 
    void VariantAssign(const T& rhs, double)
    {
        Private::SafeAssign(*this, rhs);
    }
    
    // Assignment from another Variant instantiation
    template <class TList2, typename Align2>
    void VariantAssign(const Variant<TList2, Align2>& rhs, int)
    {
        Private::SafeAssign(*this, rhs);
    }
    
public:
    // VC7 don't support partial ordering
    template <class T> 
    Variant& operator=(const T& rhs)
    {
        // Both VariantAssign are the same in this implementation
        VariantAssign(rhs, int(0));
        return *this;
    }

    // ~
    ~Variant()
    {
        (vptr_->destroy_)(*this);
    }

    // Visitors definitions
    // @@@ Possible improvement: add defintions of visitor who return
    //     something else than void

    typedef ::Loki::Visitor<TList, void> StrictVisitor;
    typedef ::Loki::Visitor<typename MakeConst<TList>::Result, void>
        ConstStrictVisitor;
    typedef ::Loki::NonStrictVisitor<TList, void> NonStrictVisitor;
    typedef ::Loki::NonStrictVisitor<typename MakeConst<TList>::Result, void> 
        ConstNonStrictVisitor;

private:
    // VTable structure
    // The essential component of the fake vtable idiom, VTable contains
    // pointers to functions, pointers that will be filled up with addresses
    // of functions in VTableImpl

    struct VTable
    {
        const std::type_info& (*typeId_)();
        void (*destroy_)(const Variant&);
        void (*clone_)(const Variant&, Variant&);
        void (*swap_)(void* lhs, void* rhs);
        void (*accept_)(Variant&, StrictVisitor&);
        void (*acceptConst_)(const Variant&, ConstStrictVisitor&);
    };

    // VTable concrete implementations
    // VTableImpl<T> contains definitions for all of a VTable's pointer to
    // functions.

    // VC7 thinks that Variant inside VTableImpl is template
    typedef Variant VariantType;

    template <class T>
    struct VTableImpl
    {
    private:
        static const std::type_info& TypeId()
        {
            return typeid(T);
        }
        
        static void Destroy(const VariantType& var)
        {
            const T& data = *reinterpret_cast<const T*>(&var.buffer_[0]);
            (void)data.~T();
        }
        
        static void Swap(void* lhs, void* rhs)
        {
            Private::SwapHelper(*static_cast<T*>(lhs), *static_cast<T*>(rhs));
        }

        static void Clone(const VariantType& src, VariantType& dest)
        {
            new(&dest.buffer_[0]) T(
                *reinterpret_cast<const T*>(&src.buffer_[0]));
            dest.vptr_ = src.vptr_;
        }
                
        static void Accept(VariantType& var, StrictVisitor& visitor)
        {
            typedef typename StrictVisitor::ReturnType RType;
            ::Loki::Visitor<T,RType> &v = visitor;

            v.Visit(*reinterpret_cast<T*>(&var.buffer_[0]));
        }        
        
        static void AcceptConst(const VariantType& var, ConstStrictVisitor& visitor)
        {
            typedef typename ConstStrictVisitor::ReturnType RType;
            ::Loki::Visitor<const T,RType> &v = visitor;

            v.Visit(*reinterpret_cast<const T*>(&var.buffer_[0]));
        }        

    public:
        static const VTable *GetVPTR()
        {
            static const VTable vTbl_ =
            {
                &TypeId,
                &Destroy,
                &Clone,
                &Swap,
                &Accept,
                &AcceptConst,
            };

            return &vTbl_;
        }
    };

    template <class T> friend struct VTableImpl;

private:   // should be private; some compilers prefer 'public' :o}

    enum { neededSize = MaxSize<TList>::result };

    VTable const * vptr_;
    union
    {
        Align dummy_;
        char buffer_[neededSize];
    };
    
public:
    void swap(Variant& rhs)
    {
        if (this->TypeId() == rhs.TypeId())
        {
            (vptr_->swap_)(this->buffer_, rhs.buffer_);
        }
        else
        {
            Private::SafeSwap(*this, rhs);
        }
    }
    
    const std::type_info& TypeId() const
    {
        return (vptr_->typeId_)();
    }
    
    template <typename T> T* GetPtr()
    {
        return TypeId() == typeid(T) 
            ? reinterpret_cast<T*>(&buffer_[0])
            : 0;
    }
    
    template <typename T> const T* GetPtr() const
    {
        return TypeId() == typeid(T) 
            ? reinterpret_cast<const T*>(&buffer_[0])
            : 0;
    }
    
    template <typename T> T& Get()
    {
        T* p = GetPtr<T>();
        if (!p) throw std::runtime_error("Variant::Get() Invalid variant type");
        return *p;
    }
    
    template <typename T> const T& Get() const
    {
        const T* p = GetPtr<T>();
        if (!p) throw std::runtime_error("Variant::Get() const Invalid variant type");
        return *p;
    }

    // Visitation primitives
    // Although there are four visitor types, only two Accept functions are 
    // necessary, because the non-strict visitors inherit the strict visitors

    void Accept(StrictVisitor& visitor)
    {
        (vptr_->accept_)(*this, visitor);
    }

    void Accept(ConstStrictVisitor& visitor) const
    {
        (vptr_->acceptConst_)(*this, visitor);
    }

    // Extracts the value of a Variant converted to a specific type

    template <class To> To ConvertTo() const
    {
        typename ConverterTo<Variant, To>::Visitor v;
        ConstStrictVisitor& visitor = v;
        this->Accept(visitor);
        return v.GetDestination();
    }

    // Changes the type of a Variant in-place

    template <class To> void ChangeType()
    {
        Variant(this->ConvertTo<To>()).swap(*this);
    }

};

////////////////////////////////////////////////////////////////////////////////
// Change log:
// July 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -