OpenMW
apps/opencs/model/world/record.hpp
Go to the documentation of this file.
00001 #ifndef CSM_WOLRD_RECORD_H
00002 #define CSM_WOLRD_RECORD_H
00003 
00004 #include <stdexcept>
00005 
00006 namespace CSMWorld
00007 {
00008     struct RecordBase
00009     {
00010         enum State
00011         {
00012             State_BaseOnly = 0, // defined in base only
00013             State_Modified = 1, // exists in base, but has been modified
00014             State_ModifiedOnly = 2, // newly created in modified
00015             State_Deleted = 3, // exists in base, but has been deleted
00016             State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted)
00017         };
00018 
00019         State mState;
00020 
00021         virtual ~RecordBase();
00022 
00023         virtual RecordBase *clone() const = 0;
00024 
00025         virtual void assign (const RecordBase& record) = 0;
00027 
00028         bool isDeleted() const;
00029 
00030         bool isErased() const;
00031 
00032         bool isModified() const;
00033     };
00034 
00035     template <typename ESXRecordT>
00036     struct Record : public RecordBase
00037     {
00038         ESXRecordT mBase;
00039         ESXRecordT mModified;
00040 
00041         virtual RecordBase *clone() const;
00042 
00043         virtual void assign (const RecordBase& record);
00044 
00045         const ESXRecordT& get() const;
00047 
00048         ESXRecordT& get();
00050 
00051         const ESXRecordT& getBase() const;
00053 
00054         void setModified (const ESXRecordT& modified);
00056 
00057         void merge();
00059     };
00060 
00061     template <typename ESXRecordT>
00062     RecordBase *Record<ESXRecordT>::clone() const
00063     {
00064         return new Record<ESXRecordT> (*this);
00065     }
00066 
00067     template <typename ESXRecordT>
00068     void Record<ESXRecordT>::assign (const RecordBase& record)
00069     {
00070         *this = dynamic_cast<const Record<ESXRecordT>& > (record);
00071     }
00072 
00073     template <typename ESXRecordT>
00074     const ESXRecordT& Record<ESXRecordT>::get() const
00075     {
00076         if (mState==State_Erased)
00077             throw std::logic_error ("attempt to access a deleted record");
00078 
00079         return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified;
00080     }
00081 
00082     template <typename ESXRecordT>
00083     ESXRecordT& Record<ESXRecordT>::get()
00084     {
00085         if (mState==State_Erased)
00086             throw std::logic_error ("attempt to access a deleted record");
00087 
00088         return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified;
00089     }
00090 
00091     template <typename ESXRecordT>
00092     const ESXRecordT& Record<ESXRecordT>::getBase() const
00093     {
00094         if (mState==State_Erased)
00095             throw std::logic_error ("attempt to access a deleted record");
00096 
00097         return mState==State_ModifiedOnly ? mModified : mBase;
00098     }
00099 
00100     template <typename ESXRecordT>
00101     void Record<ESXRecordT>::setModified (const ESXRecordT& modified)
00102     {
00103         if (mState==State_Erased)
00104             throw std::logic_error ("attempt to modify a deleted record");
00105 
00106         mModified = modified;
00107 
00108         if (mState!=State_ModifiedOnly)
00109             mState = State_Modified;
00110     }
00111 
00112     template <typename ESXRecordT>
00113     void Record<ESXRecordT>::merge()
00114     {
00115         if (isModified())
00116         {
00117             mBase = mModified;
00118             mState = State_BaseOnly;
00119         }
00120         else if (mState==State_Deleted)
00121         {
00122             mState = State_Erased;
00123         }
00124     }
00125 }
00126 
00127 #endif