1 #ifndef CSM_WOLRD_RECORD_H 2 #define CSM_WOLRD_RECORD_H 3 4 #include <stdexcept> 5 6 namespace CSMWorld 7 { 8 struct RecordBase 9 { 10 enum State 11 { 12 State_BaseOnly = 0, // defined in base only 13 State_Modified = 1, // exists in base, but has been modified 14 State_ModifiedOnly = 2, // newly created in modified 15 State_Deleted = 3, // exists in base, but has been deleted 16 State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted) 17 }; 18 19 State mState; 20 21 virtual ~RecordBase(); 22 23 virtual RecordBase *clone() const = 0; 24 25 virtual RecordBase *modifiedCopy() const = 0; 26 27 virtual void assign (const RecordBase& record) = 0; 28 ///< Will throw an exception if the types don't match. 29 30 bool isDeleted() const; 31 32 bool isErased() const; 33 34 bool isModified() const; 35 }; 36 37 template <typename ESXRecordT> 38 struct Record : public RecordBase 39 { 40 ESXRecordT mBase; 41 ESXRecordT mModified; 42 43 Record(); 44 45 Record(State state, 46 const ESXRecordT *base = 0, const ESXRecordT *modified = 0); 47 48 RecordBase *clone() const override; 49 50 RecordBase *modifiedCopy() const override; 51 52 void assign (const RecordBase& record) override; 53 54 const ESXRecordT& get() const; 55 ///< Throws an exception, if the record is deleted. 56 57 ESXRecordT& get(); 58 ///< Throws an exception, if the record is deleted. 59 60 const ESXRecordT& getBase() const; 61 ///< Throws an exception, if the record is deleted. Returns modified, if there is no base. 62 63 void setModified (const ESXRecordT& modified); 64 ///< Throws an exception, if the record is deleted. 65 66 void merge(); 67 ///< Merge modified into base. 68 }; 69 70 template <typename ESXRecordT> Record()71 Record<ESXRecordT>::Record() 72 : mBase(), mModified() 73 { } 74 75 template <typename ESXRecordT> Record(State state,const ESXRecordT * base,const ESXRecordT * modified)76 Record<ESXRecordT>::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) 77 { 78 if(base) 79 mBase = *base; 80 81 if(modified) 82 mModified = *modified; 83 84 this->mState = state; 85 } 86 87 template <typename ESXRecordT> modifiedCopy() const88 RecordBase *Record<ESXRecordT>::modifiedCopy() const 89 { 90 return new Record<ESXRecordT> (State_ModifiedOnly, nullptr, &(this->get())); 91 } 92 93 template <typename ESXRecordT> clone() const94 RecordBase *Record<ESXRecordT>::clone() const 95 { 96 return new Record<ESXRecordT> (*this); 97 } 98 99 template <typename ESXRecordT> assign(const RecordBase & record)100 void Record<ESXRecordT>::assign (const RecordBase& record) 101 { 102 *this = dynamic_cast<const Record<ESXRecordT>& > (record); 103 } 104 105 template <typename ESXRecordT> get() const106 const ESXRecordT& Record<ESXRecordT>::get() const 107 { 108 if (mState==State_Erased) 109 throw std::logic_error ("attempt to access a deleted record"); 110 111 return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified; 112 } 113 114 template <typename ESXRecordT> get()115 ESXRecordT& Record<ESXRecordT>::get() 116 { 117 if (mState==State_Erased) 118 throw std::logic_error ("attempt to access a deleted record"); 119 120 return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified; 121 } 122 123 template <typename ESXRecordT> getBase() const124 const ESXRecordT& Record<ESXRecordT>::getBase() const 125 { 126 if (mState==State_Erased) 127 throw std::logic_error ("attempt to access a deleted record"); 128 129 return mState==State_ModifiedOnly ? mModified : mBase; 130 } 131 132 template <typename ESXRecordT> setModified(const ESXRecordT & modified)133 void Record<ESXRecordT>::setModified (const ESXRecordT& modified) 134 { 135 if (mState==State_Erased) 136 throw std::logic_error ("attempt to modify a deleted record"); 137 138 mModified = modified; 139 140 if (mState!=State_ModifiedOnly) 141 mState = State_Modified; 142 } 143 144 template <typename ESXRecordT> merge()145 void Record<ESXRecordT>::merge() 146 { 147 if (isModified()) 148 { 149 mBase = mModified; 150 mState = State_BaseOnly; 151 } 152 else if (mState==State_Deleted) 153 { 154 mState = State_Erased; 155 } 156 } 157 } 158 159 #endif 160