diff --git a/Code/Mantid/Framework/DataObjects/CMakeLists.txt b/Code/Mantid/Framework/DataObjects/CMakeLists.txt index eb6c7317f71c3a165cb9d9c8d038d709acc2bdbe..2013657a5611131dd8c8b62845845bc68072804d 100644 --- a/Code/Mantid/Framework/DataObjects/CMakeLists.txt +++ b/Code/Mantid/Framework/DataObjects/CMakeLists.txt @@ -19,6 +19,9 @@ set ( SRC_FILES src/TableColumn.cpp src/TableWorkspace.cpp src/Workspace2D.cpp + src/WorkspaceMemento.cpp + src/WorkspaceMementoCollection.cpp + src/WorkspaceMementoItem.cpp src/WorkspaceSingleValue.cpp ) @@ -51,6 +54,9 @@ set ( INC_FILES inc/MantidDataObjects/TablePointerColumn.h inc/MantidDataObjects/TableWorkspace.h inc/MantidDataObjects/Workspace2D.h + inc/MantidDataObjects/WorkspaceMemento.h + inc/MantidDataObjects/WorkspaceMementoCollection.h + inc/MantidDataObjects/WorkspaceMementoItem.h inc/MantidDataObjects/WorkspaceSingleValue.h ) @@ -77,6 +83,9 @@ set ( TEST_FILES test/WeightedEventNoTimeTest.h test/WeightedEventTest.h test/Workspace2DTest.h + test/WorkspaceMementoTest.h + test/WorkspaceMementoCollectionTest.h + test/WorkspaceMementoItemTest.h test/WorkspaceIteratorTest.h test/WorkspaceSingleValueTest.h test/WorkspaceValidatorsTest.h diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h index a21239882baca70ecd46d025addc3d754584ce71..e2d6bea481cb2501620621b1f1573cd7abd426ff 100644 --- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h @@ -51,6 +51,9 @@ namespace DataObjects /// Must return overall memory size taken by the column. virtual long int sizeOfData()const; + /// Clone. + virtual PeakColumn* clone() const; + protected: /// Sets the new column size. virtual void resize(int count); diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h index d68e30b64a4f7e1940f6971cabff5c4a6fc21eff..a5555aa9fa701fc4f37446507680e31418957baf 100644 --- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h @@ -85,6 +85,14 @@ public: bool isBool()const{return typeid(Type) == typeid(API::Boolean);} /// Memory used by the column long int sizeOfData()const{return static_cast<long int>(m_data.size()*sizeof(Type));} + /// Clone + virtual TableColumn* clone() const + { + TableColumn* temp = new TableColumn(); + temp->m_data = this->m_data; + temp->setName(this->m_name); + return temp; + } /// Reference to the data. std::vector<Type>& data(){return m_data;} diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TablePointerColumn.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TablePointerColumn.h index 08544d31088c399dc6f939fe407c40771c5115fc..8e6856d01266e8780918e21825d7ea8f95a97709 100644 --- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TablePointerColumn.h +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TablePointerColumn.h @@ -75,6 +75,13 @@ public: bool isBool()const{return typeid(Type) == typeid(API::Boolean);} /// Memory used by the column long int sizeOfData()const{return static_cast<long int>(m_data.size()*sizeof(Type));} + /// Clone + virtual TablePointerColumn* clone() const + { + TablePointerColumn* temp = new TablePointerColumn(); + temp->m_data = this->m_data; + return temp; + } protected: /// Resize. void resize(int count) diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableWorkspace.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableWorkspace.h index 38c9c6dd465fa33feace2e6b76c3d3f3b46ff1e2..12a6175e36022199b13b62fd6eda37fe525ba223 100644 --- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableWorkspace.h +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/TableWorkspace.h @@ -95,7 +95,6 @@ namespace DataObjects virtual const std::string id() const{return "TableWorkspace";} /// Get the footprint in memory in KB. virtual size_t getMemorySize() const; - /// Creates a new column. bool addColumn(const std::string& type, const std::string& name); /// Removes a column. @@ -118,6 +117,8 @@ namespace DataObjects int insertRow(int index); /// Delets a row if it exists. void removeRow(int index); + /// Clone table workspace instance. + TableWorkspace* clone() const; /** This method finds the row and column index of an integer cell value in a table workspace * @param value :: -value to search @@ -209,7 +210,9 @@ private: throw; } } - + + bool addColumn(boost::shared_ptr<API::Column> column); + /** This method finds the row and column index of an integer cell value in a table workspace * @param value :: -value to search * @param row row number of the value searched diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMemento.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMemento.h new file mode 100644 index 0000000000000000000000000000000000000000..2730c8b1b46d7142fb5dadcbf8d11e3bc4420064 --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMemento.h @@ -0,0 +1,112 @@ +#ifndef MANTID_DATAOBJECTS_MEMENTO_H_ +#define MANTID_DATAOBJECTS_MEMENTO_H_ + +#include "MantidKernel/System.h" +#include "MantidDataObjects/WorkspaceMementoItem.h" +#include <string> +#include <vector> +#include <map> +#include <boost/scoped_ptr.hpp> + +namespace Mantid +{ + namespace DataObjects + { + /** + Abstract Functor for locking usage. + */ + class DLLExport WorkspaceMementoLock + { + public: + virtual void lock() = 0; + virtual bool unlock() = 0; + virtual bool locked() const = 0; + virtual ~WorkspaceMementoLock(){} + }; + + /** + Concrete locking functor implementing single-owner-usage for locking. + */ + class DLLExport SingleOwnerLock : public WorkspaceMementoLock + { + private: + typedef std::map<size_t, bool> LockMap; + static LockMap locks; + size_t m_runNumber; + public: + SingleOwnerLock(size_t runNumber); + virtual void lock(); + virtual bool unlock(); + virtual bool locked() const; + virtual ~SingleOwnerLock(); + }; + + /** @class WorkspaceMemento + + Stores local changes to Workspace metadata. Can commit or rollback these changes to an underlying table workspace, + which encapsulates all changes to a set of related workspaces (see WorkspaceMementoCollection). + + @author Owen Arnold + @date 30/08/2011 + + Copyright © 2007-8 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ + class DLLExport WorkspaceMemento + { + public: + + typedef std::vector<AbstractMementoItem_sptr> VecMementoItems; + WorkspaceMemento(TableWorkspace& ws, size_t runNumber); + WorkspaceMemento(TableWorkspace& ws, size_t runNumber, WorkspaceMementoLock* lock); + ~WorkspaceMemento(); + void addItem(AbstractMementoItem* item); + AbstractMementoItem_sptr getItem(const size_t col) const; + void commit(); + void rollback(); + bool hasChanged() const; + void validate() const; + bool equals(const WorkspaceMemento& workspace) const; + bool operator==(const WorkspaceMemento& workspace) const; + bool operator!=(const WorkspaceMemento& workspace) const; + bool locked() const; + bool unlock(); + void lock(); + private: + /// Reference to underlying data. + const TableWorkspace& m_data; + /// Memento items to store local/un-saved changes. + VecMementoItems m_items; + /// Flag indicating memento is valid. + bool m_validMemento; + /// Run number associated with this memento. + size_t m_runNumber; + /// Disabled copy constructor. + WorkspaceMemento(const WorkspaceMemento&); + /// Disabled assignement operator. + WorkspaceMemento& operator=(const WorkspaceMemento&); + /// Locking object. + boost::scoped_ptr<WorkspaceMementoLock> m_lock; + + }; + } +} + +#endif \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoCollection.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoCollection.h new file mode 100644 index 0000000000000000000000000000000000000000..e86336d1387f233fdd852ff7ecab55322f58330e --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoCollection.h @@ -0,0 +1,88 @@ +#ifndef MANTID_DATAOBJECTS_MEMENTO_COLLECTION_H_ +#define MANTID_DATAOBJECTS_MEMENTO_COLLECTION_H_ + +#include "MantidDataObjects/WorkspaceMemento.h" +#include <boost/scoped_ptr.hpp> + +namespace Mantid +{ + namespace API + { + class Workspace; + } + namespace DataObjects + { + /// Locking proxy smart pointer. Ensures that Workspace Mementos are always locked and unlocked. + class DLLExport LockingMemento { + public: + LockingMemento (WorkspaceMemento *memento) : m_memento (memento) + { + m_memento->lock(); + } + WorkspaceMemento * operator -> () + { + return m_memento; + } + ~LockingMemento () + { + m_memento->unlock(); + delete m_memento; + } + private: + WorkspaceMemento* m_memento; + }; + + + /** @class WorkspaceMementoCollection + + Stores all changes to registerd workspace in-terms of a diff-table (TableWorkspace). The final diff table can be exported and used + to generate a series of workspaces encapsulating all the changes described within the table. + + Main workflow + + -Register workspaces via method call ::registerWorkspace + -Fetch workspace mementos via method call ::at + -Serialize changes via method call ::serialize + + Mementos are returned in a Locked format, meaning that no other memento may change that table row (corresponding to an individual run/workspace). + Once the fields are changed on the memento, changes may be committed or rolled-back. These operations occur directly on the diff table contained within the MementoCollection. + The Memento collection does NOT own memento objects, it is a factory for them. + + @author Owen Arnold + @date 26/08/2011 + + Copyright © 2011-12 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ + class DLLExport WorkspaceMementoCollection + { + public: + WorkspaceMementoCollection(); + ~WorkspaceMementoCollection(); + void registerWorkspace(const Mantid::API::Workspace& ws); + LockingMemento at(size_t runNumber); + TableWorkspace* serialize() const; + private: + TableWorkspace m_data; + }; + } +} + +#endif \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoItem.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoItem.h new file mode 100644 index 0000000000000000000000000000000000000000..c574ea8c61b10e6175c19261d0b5c3eb15313d6c --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/WorkspaceMementoItem.h @@ -0,0 +1,207 @@ +#ifndef MANTID_DATAOBJECTS_MEMENTO_ITEM_H_ +#define MANTID_DATAOBJECTS_MEMENTO_ITEM_H_ +#include "MantidKernel/System.h" +#include "MantidDataObjects/TableWorkspace.h" +#include "boost/shared_ptr.hpp" + +namespace Mantid +{ + namespace DataObjects + { + + + /** @class Boolean + As TableColumn stores its data in a std::vector bool type cannot be used + in the same way as the other types. Class Boolean is used instead. +*/ + class DLLExport AbstractMementoItem + { + public: + virtual bool hasChanged() const = 0; + virtual void commit() = 0; + virtual void rollback() = 0; + virtual bool equals(AbstractMementoItem& other) const = 0; + virtual ~AbstractMementoItem() {} + }; + + + typedef boost::shared_ptr<AbstractMementoItem> AbstractMementoItem_sptr; + + /** @class WorkspaceMementoItem. Unique type for column data, through which changes to cell data can be applied, stored and reverted. + Type system ensures that no two columns are comparible, even if they store the same data. + + + @author Owen Arnold + @date 25/08/2011 + + Copyright © 2011-12 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ + template<int ColNumber, typename ColType> + class DLLExport WorkspaceMementoItem : public AbstractMementoItem + { + private: + /// Actual/outstanding value stored in cell. + ColType m_value; + /// Reference to mutable table workspace. + TableWorkspace& m_data; + /// Row onto which this column object projects. + size_t m_rowIndex; + + public: + /// Unique column index. + enum { ColIndex = ColNumber }; + /// Type of item being stored. + typedef ColType ItemType; + + /** + Constructor + @param data : ref to table workspace storing the data. + @param rowIndex : index of the row in the table workspace that this column/memento item. is to apply. + */ + WorkspaceMementoItem(TableWorkspace& data, size_t rowIndex) : m_data(data), m_rowIndex(rowIndex) + { + m_value = m_data.getColumn(ColIndex)->cell<ColType>(m_rowIndex); + } + + /** + Copy constructor + @param other : memento item to copy from. + */ + WorkspaceMementoItem(const WorkspaceMementoItem& other) : m_value(other.m_value), m_data(other.m_data), m_rowIndex(other.m_rowIndex) + { + } + + /** + Overrriden assignement operator. + @param other : memento item to assign from. + */ + WorkspaceMementoItem& operator=(const WorkspaceMementoItem& other) + { + if(&other != this) + { + m_value = other.m_value; + m_rowIndex = other.m_rowIndex; + } + return *this; + } + + /// Destructor + virtual ~WorkspaceMementoItem() + { + } + + /* + Getter for changed status. + @return true if different. + */ + virtual bool hasChanged() const + { + return m_data.getColumn(ColIndex)->cell<ColType>(m_rowIndex) != m_value; + } + + /* + Abstract equals operator. Templated type indepenedent in interface. + @param other : Abstract memento item to compare against. + @return true if equal. + @throw runtime error if type mismatch. + */ + bool equals(AbstractMementoItem& other) const + { + WorkspaceMementoItem* pOther = dynamic_cast<WorkspaceMementoItem<ColNumber, ColType>* >(&other); + if(pOther == NULL) + { + throw std::runtime_error("Cannot call AbstractMementoItem::equals() on incompatible types."); + } + else + { + return equals(*pOther); + } + } + + /** + Strongly typed equals operator. + @param other : ref to other (same exact type) workspace memento item to compare against. + @return true if same. + */ + bool equals(const WorkspaceMementoItem& other) const + { + return m_value == other.m_value; + } + + /** + Equals operator. + @param other : ref to other (same exact type) workspace memento item to compare against. + @return true if same. + */ + bool operator==(const WorkspaceMementoItem& other) const + { + return equals(other); + } + + /** + Not equals operator. + @param other : ref to other (same exact type) workspace memento item to compare against. + @return true if not same. + */ + bool operator!=(const WorkspaceMementoItem& other) const + { + return !equals(other); + } + + /** + Set the internal value. This is a reversable operation. + @value : value to set on memento item. + */ + void setValue(ColType value) + { + m_value = value; + } + + + /// Synchronise the changes (via setvalue) with the underlying table workspace. This is a non reversible operation. + void commit() + { + m_data.getColumn(ColIndex)->cell<ColType>(m_rowIndex) = m_value; + } + + /// Undo changes via setValue. + void rollback() + { + m_value = m_data.getColumn(ColIndex)->cell<ColType>(m_rowIndex); + } + + /** + Get the value. + @return value. + */ + ColType getValue() const + { + return m_value; //TODO, should we be returning the set value or the commited value. + } + + }; + + } +} + + + +#endif \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/src/PeakColumn.cpp b/Code/Mantid/Framework/DataObjects/src/PeakColumn.cpp index 6f051e3bff874cbd5145f439f3bb8d839b5fd207..c941ff76762171baf76a935d394f59fa178b9586 100644 --- a/Code/Mantid/Framework/DataObjects/src/PeakColumn.cpp +++ b/Code/Mantid/Framework/DataObjects/src/PeakColumn.cpp @@ -166,6 +166,12 @@ namespace DataObjects throw std::runtime_error("const version of void_pointer() not implemented. Looks to be unused?"); } + PeakColumn* PeakColumn::clone() const + { + PeakColumn* temp = new PeakColumn(this->peaks, this->m_name); + return temp; + } + } // namespace Mantid } // namespace DataObjects diff --git a/Code/Mantid/Framework/DataObjects/src/TableWorkspace.cpp b/Code/Mantid/Framework/DataObjects/src/TableWorkspace.cpp index 2241cfa1464697e0dadc5ff351144366ce8cfc44..10f1b3b7dd0460ad033d0308d34398caf16760d5 100644 --- a/Code/Mantid/Framework/DataObjects/src/TableWorkspace.cpp +++ b/Code/Mantid/Framework/DataObjects/src/TableWorkspace.cpp @@ -173,6 +173,32 @@ namespace Mantid return nameList; } + bool TableWorkspace::addColumn(boost::shared_ptr<API::Column> column) + { + column_it ci = std::find_if(m_columns.begin(),m_columns.end(),FindName(column->name())); + if (ci != m_columns.end()) + { + g_log.error()<<"Column with name "<<column->name()<<" already exists.\n"; + return false; + } + else + { + m_columns.push_back(column); + } + } + + TableWorkspace* TableWorkspace::clone() const + { + TableWorkspace* copy = new TableWorkspace(this->m_rowCount); + column_const_it it=m_columns.begin(); + while(it != m_columns.end()) + { + copy->addColumn(boost::shared_ptr<API::Column>((*it)->clone())); + it++; + } + return copy; + }; + // template<> // boost::tuples::null_type TableWorkspace::make_TupleRef< boost::tuples::null_type >(int j,const std::vector<std::string>& names,int i) // {return boost::tuples::null_type();} diff --git a/Code/Mantid/Framework/DataObjects/src/WorkspaceMemento.cpp b/Code/Mantid/Framework/DataObjects/src/WorkspaceMemento.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4caa19d45c10253efade628c4bd1c8936be20d40 --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/src/WorkspaceMemento.cpp @@ -0,0 +1,226 @@ +#include "MantidDataObjects/WorkspaceMemento.h" + +namespace Mantid +{ + namespace DataObjects + { + + /** + Constructor + @param ws : ref to underlying table workspace where persisted data is stored. + @param runNumber : the run number corresponding to this memento. + */ + WorkspaceMemento::WorkspaceMemento(TableWorkspace& ws, size_t runNumber) : + m_data(ws), + m_validMemento(false), + m_runNumber(runNumber), + m_lock(new SingleOwnerLock(runNumber)) + { + } + + /** + Constructor with option to specify locking object. + @param ws : ref to underlying table workspace where persisted data is stored. + @param runNumber : the run number corresponding to this memento. + @param lock : locking object to use internally. + */ + WorkspaceMemento::WorkspaceMemento(TableWorkspace& ws, size_t runNumber, WorkspaceMementoLock* lock) : + m_data(ws), + m_validMemento(false), + m_runNumber(runNumber), + m_lock(lock) + { + } + + /// Destructor + WorkspaceMemento::~WorkspaceMemento() + { + } + + /* Add a metadata item. This corresponds to a cell in the underlying table workspace. + @param item : Abstract memento item shared pointer. + */ + void WorkspaceMemento::addItem(AbstractMementoItem* item) + { + //TODO check types here. Type of item should be the same as the corresponding colum in the table. + AbstractMementoItem_sptr temp(item); + m_items.push_back(temp); + m_items.size() == m_data.columnCount() ? m_validMemento = true : m_validMemento = false; + } + + /* Getter for the item at a column + @return Abstract memento item shared pointer. + */ + AbstractMementoItem_sptr WorkspaceMemento::getItem(const size_t col) const + { + return m_items[col]; + } + + /** + Getter for the locked status. + @return locked status. + */ + bool WorkspaceMemento::locked() const + { + return m_lock->locked(); + } + + /// Request the memento and underlying data are locked. + void WorkspaceMemento::lock() + { + return m_lock->lock(); + } + + /** + Unlock the memento. + @return true if sucessfully unlocked, false if already unlocked. + */ + bool WorkspaceMemento::unlock() + { + return m_lock->unlock(); + } + + /// Validate the workspace. Ensure that it is well-setup before using as a memento. + void WorkspaceMemento::validate() const + { + if(!m_validMemento) + { + throw std::runtime_error("Cannot use this type without first having set it up using ::addItem"); + } + } + + /** + Getter indicating if there are changes not yet persisted to the underlying table workspace. + @return true if outstanding changes exist. + */ + bool WorkspaceMemento::hasChanged() const + { + validate(); + //Run through each memento item for its changed status. + VecMementoItems::const_iterator it = m_items.begin(); + while(it != m_items.end()) + { + if((*it)->hasChanged()){ return true; } + it++; + } + return false; + } + + /** + Equals comparitor for this instance with another memento. + @param other : another workspace memento to compare to. + @return true if equal. + */ + bool WorkspaceMemento::equals(const WorkspaceMemento& other) const + { + validate(); + bool bResult = false; + if(this->m_items.size() != other.m_items.size()) + { + return bResult; + } + for(size_t i = 0; i < m_items.size(); i++) + { + //Defer to each memento item. + bResult = m_items[i]->equals(*other.m_items[i]); + if(!bResult) + break; + } + return bResult; + } + + /** + Equals operator overload. + @param other : another workspace memento to compare to. + @return true if equal. + */ + bool WorkspaceMemento::operator==(const WorkspaceMemento& other) const + { + return this->equals(other); + } + + /** + Not equals operator overload. + @param other : another workspace memento to compare to. + @return false if equal. + */ + bool WorkspaceMemento::operator!=(const WorkspaceMemento& other) const + { + return !this->equals(other); + } + + /// Commit changes + void WorkspaceMemento::commit() + { + validate(); + VecMementoItems::const_iterator it = m_items.begin(); + while(it != m_items.end()) + { + (*it)->commit(); + it++; + } + } + + /// Roll back changes + void WorkspaceMemento::rollback() + { + validate(); + VecMementoItems::const_iterator it = m_items.begin(); + while(it != m_items.end()) + { + (*it)->rollback(); + it++; + } + } + + // ------------------ TODO split following off into separate cpp ---------------- + + SingleOwnerLock::LockMap SingleOwnerLock::locks; + + SingleOwnerLock::SingleOwnerLock(size_t runNumber) : m_runNumber(runNumber) {} + + /// Apply the lock. + void SingleOwnerLock::lock() + { + //You could get a race condition in the following, but this code is not intended for parallel usage. + if(locked()) + { + throw std::runtime_error("This memento is already in use!"); + } + SingleOwnerLock::locks[m_runNumber] = true; + } + + /** + Remove the lock. + @return true if locked when unlocked. Returns false if already unlocked. + */ + bool SingleOwnerLock::unlock() + { + bool existingState = SingleOwnerLock::locks[m_runNumber]; + SingleOwnerLock::locks[m_runNumber] = false; + return existingState; + } + + /** + Getter for the locked status. + @return true if locked. + */ + bool SingleOwnerLock::locked() const + { + LockMap::iterator it = SingleOwnerLock::locks.find(m_runNumber); + if(SingleOwnerLock::locks.end() != it) + { + return it->second; + } + return false; + } + + /// Destructor + SingleOwnerLock::~SingleOwnerLock() + { + //Remove the lock if not done so already. + if(locked()) + unlock(); + } + } +} \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoCollection.cpp b/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoCollection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af068ed39fc3635878ad3aef19298e942d1bbdff --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoCollection.cpp @@ -0,0 +1,66 @@ +#include "MantidDataObjects/WorkspaceMementoCollection.h" +#include "MantidDataObjects/TableWorkspace.h" +#include "MantidAPI/TableRow.h" +#include "MantidDataObjects/WorkspaceMemento.h" + +namespace Mantid +{ + namespace DataObjects + { + /// Constructor + WorkspaceMementoCollection::WorkspaceMementoCollection() + { + //Define the table schema here + m_data.addColumn("str", "WorkspaceName"); + //TODO, lots more columns will be required here. + } + + /** + Register a workspace so that mementos may be generated from it. + @param ws : ref to workspace to generate mementos for. + */ + void WorkspaceMementoCollection::registerWorkspace(const Mantid::API::Workspace& ws) + { + using namespace API; + //Add row to table. + m_data.insertRow(m_data.rowCount() + 1); + TableRow row = m_data.getRow(m_data.rowCount()-1); + row << ws.getName(); + } + + /** + Gets the workspace memento at a designated runnumber. + Workspace mementos are returned in locking smart pointers to ensure that there is no accidental duplicate access. + @param runNumber : The run number. + @return locking smart pointer wrapping workspace memento. + */ + LockingMemento WorkspaceMementoCollection::at(size_t runNumber) + { + WorkspaceMemento* memento = new WorkspaceMemento(m_data, runNumber); + + //Table schema should be identical to that described in constructor. + + memento->addItem(new WorkspaceMementoItem<0, std::string>(m_data, runNumber)); + //TODO lots more column items to add. + + //Wrap product and return. + return LockingMemento(memento); + } + + /** + Serializes workspace changes to xml. + @return serialized table workspace containing all diffs. + */ + TableWorkspace* WorkspaceMementoCollection::serialize() const + { + //TODO, should hasChanges be checked first? Presumbably we need to ensure that all mementos are in an unmodified state before this is allowed. + return m_data.clone(); + } + + /// Destructor + WorkspaceMementoCollection::~WorkspaceMementoCollection() + { + } + + } +} \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoItem.cpp b/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54dc1dba817da77c1e334753c94c8d95e03aa6c1 --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/src/WorkspaceMementoItem.cpp @@ -0,0 +1,9 @@ +#include "MantidDataObjects/WorkspaceMementoItem.h" + +namespace Mantid +{ + namespace DataObjects + { + + } +} \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/test/PeakColumnTest.h b/Code/Mantid/Framework/DataObjects/test/PeakColumnTest.h index 20ec171fda183ded0d0ba35b46fc012fc456153e..71fba7a671c80d3ce65d455b100a41343ba1b9d8 100644 --- a/Code/Mantid/Framework/DataObjects/test/PeakColumnTest.h +++ b/Code/Mantid/Framework/DataObjects/test/PeakColumnTest.h @@ -24,6 +24,25 @@ public: TS_ASSERT_EQUALS( pc.size(), 0); } + void test_clone() + { + Peak a; + Peak b; + + std::vector<Peak> peaks; + peaks.push_back(a); + peaks.push_back(b); + + PeakColumn pc(peaks, "h"); + + PeakColumn* cloned = pc.clone(); + + TS_ASSERT_EQUALS(pc.name(), cloned->name()); + TS_ASSERT_EQUALS(2, cloned->size()); + + delete cloned; + } + }; diff --git a/Code/Mantid/Framework/DataObjects/test/TableWorkspaceTest.h b/Code/Mantid/Framework/DataObjects/test/TableWorkspaceTest.h index dd91cbf39c575599f1ea3a5bcf4dd630fe704756..841cfb9ddf234d6a21bec2e81263e0f21b817df3 100644 --- a/Code/Mantid/Framework/DataObjects/test/TableWorkspaceTest.h +++ b/Code/Mantid/Framework/DataObjects/test/TableWorkspaceTest.h @@ -4,6 +4,7 @@ #include <vector> #include <algorithm> #include <boost/shared_ptr.hpp> +#include <boost/scoped_ptr.hpp> #include <cxxtest/TestSuite.h> #include "MantidDataObjects/TableWorkspace.h" @@ -249,8 +250,27 @@ public: tw.find(searchstr,row,formatcol); TS_ASSERT_EQUALS(row,7); + } - + void testClone() + { + TableWorkspace tw(1); + tw.addColumn("str","X"); + tw.addColumn("str","Y"); + tw.addColumn("str","Z"); + + tw.getColumn(0)->cell<std::string>(0) = "a"; + tw.getColumn(1)->cell<std::string>(0) = "b"; + tw.getColumn(2)->cell<std::string>(0) = "c"; + + boost::scoped_ptr<TableWorkspace> cloned(tw.clone()); + + //Check clone is same as original. + TS_ASSERT_EQUALS(tw.columnCount(), cloned->columnCount()); + TS_ASSERT_EQUALS(tw.rowCount(), cloned->rowCount()); + TS_ASSERT_EQUALS("a", cloned->getColumn(0)->cell<std::string>(0)); + TS_ASSERT_EQUALS("b", cloned->getColumn(1)->cell<std::string>(0)); + TS_ASSERT_EQUALS("c", cloned->getColumn(2)->cell<std::string>(0)); } diff --git a/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoCollectionTest.h b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoCollectionTest.h new file mode 100644 index 0000000000000000000000000000000000000000..a6a4b1366475a5abba1cf9f56877fb2a714d7deb --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoCollectionTest.h @@ -0,0 +1,58 @@ +#ifndef MANTID_WORKSPACE_MEMENTO_COLLECTION_TEST_H_ +#define MANTID_WORKSPACE_MEMENTO_COLLECTION_TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidDataObjects/WorkspaceMementoCollection.h" +#include "MantidDataObjects/TableWorkspace.h" + +using namespace Mantid::DataObjects; + +class WorkspaceMementoCollectionTest : public CxxTest::TestSuite +{ +public: + + void testSerialize() + { + WorkspaceMementoCollection collection; + TableWorkspace* productA = collection.serialize(); + TableWorkspace* productB = collection.serialize(); + + TSM_ASSERT_EQUALS("Characterisation test. Current table schema has 1 column", 1, productA->columnCount()); + TSM_ASSERT_EQUALS("No workspaces registered, so should have no rows.", 0, productA->rowCount()); + TSM_ASSERT("Check are different locations on heap", productA != productB); + delete productA; + delete productB; + } + +void testRegisterWorkspace() +{ + TableWorkspace ws; + ws.setName("WSName"); + + WorkspaceMementoCollection collection; + collection.registerWorkspace(ws); //Could be any other kind of workspace. + TableWorkspace* product = collection.serialize(); + + TSM_ASSERT_EQUALS("Registered workspace property not serialized.", "WSName", product->cell<std::string>(0, 0)); + delete product; +} + +void testGetMemento() +{ + TableWorkspace ws; + ws.setName("WSName"); + + WorkspaceMementoCollection collection; + collection.registerWorkspace(ws); //Could be any other kind of workspace registered. + LockingMemento smrtPtr = collection.at(0); + boost::shared_ptr<WorkspaceMementoItem<0, std::string> > pExact = boost::dynamic_pointer_cast<WorkspaceMementoItem<0, std::string> >(smrtPtr->getItem(0)); + + TS_ASSERT(pExact != NULL); + TS_ASSERT_EQUALS("WSName", pExact->getValue()); + +} + + +}; + +#endif \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoItemTest.h b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoItemTest.h new file mode 100644 index 0000000000000000000000000000000000000000..b0fa3b940ce99623271447ff171638b017f4742d --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoItemTest.h @@ -0,0 +1,140 @@ +#ifndef MANTID_WORKSPACE_MEMENTO_ITEM_TEST_H_ +#define MANTID_WORKSPACE_MEMENTO_ITEM_TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidDataObjects/WorkspaceMementoItem.h" +#include <string> + +using Mantid::DataObjects::WorkspaceMementoItem; +using Mantid::DataObjects::TableWorkspace; + +class WorkspaceMementoItemTest : public CxxTest::TestSuite +{ + +private: + + TableWorkspace ws; + +public: + +WorkspaceMementoItemTest() : ws(2) +{ + //Set up a table workspace with one column and one row. then put a single + //value integer in that workspace with value 1. + ws.addColumn("int", "test_col1"); + ws.addColumn("int", "test_col2"); + ws.getColumn(0)->cell<int>(0) = 1; + ws.getColumn(1)->cell<int>(0) = 1; +} + +void testConstructor() +{ + //Integer Item + WorkspaceMementoItem<0, int> a(ws, 0); + TS_ASSERT_EQUALS(0, a.ColIndex); + TS_ASSERT_EQUALS(1, a.getValue()); +} + +void testEqualsThrows() +{ + typedef WorkspaceMementoItem<0, int> TypeA; + typedef WorkspaceMementoItem<1, int> TypeB; //Different column number constitutes a different type. + TypeA A(ws, 0); + TypeB B(ws, 0); + + TSM_ASSERT_THROWS("Should throw if types on which equals are called are not compatible.", A.equals(B), std::runtime_error); +} + +void testEquals() +{ + WorkspaceMementoItem<0, int> a(ws, 0); + a.setValue(2); + WorkspaceMementoItem<0, int> b(ws, 0); + b.setValue(2); + + TS_ASSERT(a.equals(b)); + TS_ASSERT(b.equals(a)); + TS_ASSERT_EQUALS(a, b); +} + +void testNotEquals() +{ + WorkspaceMementoItem<0, int> a(ws, 0); + a.setValue(2); + WorkspaceMementoItem<0, int> b(ws, 0); + b.setValue(3); + + TS_ASSERT(!a.equals(b)); + TS_ASSERT(!b.equals(a)); + TS_ASSERT_DIFFERS(a, b); + TS_ASSERT(a.operator!=(b)); +} + +void testCopy() +{ + WorkspaceMementoItem<0, int> item(ws, 0); + item.setValue(3); + WorkspaceMementoItem<0, int> copy(item); + + TS_ASSERT_EQUALS(item, copy); +} + +void testAssign() +{ + WorkspaceMementoItem<0, int> a(ws, 0); + a.setValue(3); + WorkspaceMementoItem<0, int> b(ws, 0); + b.setValue(4); + b = a; + TS_ASSERT_EQUALS(a, b); + TS_ASSERT_EQUALS(3, b.getValue()); +} + +void testSetValue() +{ + WorkspaceMementoItem<0, int> item(ws, 0); + item.setValue(2); + TS_ASSERT_EQUALS(2, item.getValue()); +} + +void testHasChanged() +{ + //create a mementoitem pointing at the same cell in the table workspace. + WorkspaceMementoItem<0, int> item(ws, 0); + TS_ASSERT(!item.hasChanged()); + item.setValue(2000); + TS_ASSERT(item.hasChanged()); +} + +void testApplyChanges() +{ + + //create a mementoitem pointing at the same cell in the table workspace. + WorkspaceMementoItem<0, int> item(ws, 0); + item.setValue(2); + + //Apply changes in memento over to the table workspace. + TS_ASSERT_THROWS_NOTHING(item.commit()); + + //Check that the chanes arrive. + TS_ASSERT_EQUALS(2, ws.getColumn(0)->cell<int>(0)); + TSM_ASSERT("Changes have been applied. Should not indicate outstanding!", !item.hasChanged()) +} + +void testRevertChanges() +{ + + //create a mementoitem pointing at the same cell in the table workspace. + WorkspaceMementoItem<0, int> item(ws, 0); + item.setValue(2); + + //Apply changes in memento over to the table workspace. + TS_ASSERT_THROWS_NOTHING(item.rollback()); + TSM_ASSERT("Changes have been reverted. Should not indicate outstanding!", !item.hasChanged()) +} + + + +}; + +#endif \ No newline at end of file diff --git a/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoTest.h b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoTest.h new file mode 100644 index 0000000000000000000000000000000000000000..fc6f6c8b0c5532f4a900466325889c40117c8b63 --- /dev/null +++ b/Code/Mantid/Framework/DataObjects/test/WorkspaceMementoTest.h @@ -0,0 +1,177 @@ +#ifndef MANTID_WORKSPACE_MEMENTO_TEST_H_ +#define MANTID_WORKSPACE_MEMENTO_TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidDataObjects/WorkspaceMemento.h" + +using namespace Mantid::DataObjects; + +class WorkspaceMementoTest : public CxxTest::TestSuite +{ + +private: + + TableWorkspace ws; + +public: + +WorkspaceMementoTest() : ws(2) +{ + //Set up a table workspace with one column and one row. then put a single + //value integer in that workspace with value 1. + ws.addColumn("int", "test_col1"); + ws.addColumn("int", "test_col2"); +} + +void setUp() +{ + ws.getColumn(0)->cell<int>(0) = 1; + ws.getColumn(1)->cell<int>(0) = 1; +} + +void testInvalidWithoutAddingItems() +{ + WorkspaceMemento memento(ws, 0); + TSM_ASSERT_THROWS("Should not be valid. No items added!", memento.validate(), std::runtime_error); +} + +void testAddItems() +{ + WorkspaceMemento memento(ws, 0); + memento.addItem(new WorkspaceMementoItem<0, int>(ws, 0)); + memento.addItem(new WorkspaceMementoItem<1, int>(ws, 0)); + TS_ASSERT_THROWS_NOTHING(memento.validate()); + TS_ASSERT(!memento.hasChanged()); +} + +void testItemHasChanged() +{ + WorkspaceMemento memento(ws, 0); + typedef WorkspaceMementoItem<0, int> ColA; + typedef WorkspaceMementoItem<1, int> ColB; + + ColA* colA = new ColA(ws, 0); + ColB* colB = new ColB(ws, 0); + + memento.addItem(colA); + memento.addItem(colB); + TS_ASSERT_THROWS_NOTHING(memento.validate()); + TS_ASSERT(!memento.hasChanged()); + + colA->setValue(9); //Set to something different. + + TSM_ASSERT("Should have registered that one of the items has changed.",memento.hasChanged()); +} + +void testItemReverted() +{ + WorkspaceMemento memento(ws, 0); + typedef WorkspaceMementoItem<0, int> ColA; + typedef WorkspaceMementoItem<1, int> ColB; + + ColA* colA = new ColA(ws, 0); + ColB* colB = new ColB(ws, 0); + + memento.addItem(colA); + memento.addItem(colB); + + colA->setValue(9); //Set to something different. + memento.rollback(); //Now rollback changes. + + TSM_ASSERT("Should have rolledback everything.", !memento.hasChanged()); +} + + +void testItemCommitted() +{ + WorkspaceMemento memento(ws, 0); + typedef WorkspaceMementoItem<0, int> ColA; + typedef WorkspaceMementoItem<1, int> ColB; + + ColA* colA = new ColA(ws, 0); + ColB* colB = new ColB(ws, 0); + + memento.addItem(colA); + memento.addItem(colB); + + colA->setValue(9); //Set to something different. + memento.commit(); //Now commit changes. + + TSM_ASSERT("Should have commited everything.", !memento.hasChanged()); +} + +void testEquals() +{ + WorkspaceMemento a(ws, 0); + a.addItem(new WorkspaceMementoItem<0, int>(ws, 0)); + a.addItem(new WorkspaceMementoItem<1, int>(ws, 0)); + + WorkspaceMemento b(ws, 0); + b.addItem(new WorkspaceMementoItem<0, int>(ws, 0)); + b.addItem(new WorkspaceMementoItem<1, int>(ws, 0)); + + TS_ASSERT(a.equals(b)); + TS_ASSERT(b.equals(a)); + TS_ASSERT(a == b); +}; + +void testNotEquals() +{ + WorkspaceMemento a(ws, 0); + a.addItem(new WorkspaceMementoItem<0, int>(ws, 0)); + a.addItem(new WorkspaceMementoItem<1, int>(ws, 0)); + + WorkspaceMemento b(ws, 0); + WorkspaceMementoItem<0, int>* colA = new WorkspaceMementoItem<0, int>(ws, 0); + b.addItem(colA); + colA->setValue(9);// Set item on b to something different. + b.addItem(new WorkspaceMementoItem<1, int>(ws, 0)); + + TS_ASSERT(!a.equals(b)); + TS_ASSERT(!b.equals(a)); + TS_ASSERT(a != b); +}; + +void testCheckLocking() +{ + WorkspaceMemento a(ws, 0); + TSM_ASSERT_THROWS_NOTHING("Lock it.", a.lock()); + TSM_ASSERT("Check it's locked", a.locked()); + TSM_ASSERT_THROWS_NOTHING("Unlock it", a.unlock()); + TSM_ASSERT("Check it's unlocked", !a.locked()); +} + +void testDuplicateLockThrows() +{ + WorkspaceMemento a(ws, 0); + TSM_ASSERT_THROWS_NOTHING("Lock it.", a.lock()); + TSM_ASSERT("Check it's locked", a.locked()); + + WorkspaceMemento b(ws, 0); + TSM_ASSERT_THROWS("Already locked, should throw.", b.lock(), std::runtime_error); + + //Clean-up + a.unlock(); + TSM_ASSERT("Check it's unlocked", !a.locked()); +} + +void testAutoUnlock() +{ + { + WorkspaceMemento a(ws, 0); + TSM_ASSERT_THROWS_NOTHING("Lock it.", a.lock()); + TSM_ASSERT("Check it's locked", a.locked()); + } + //a is out of scope, should have unlocked itself on destruction. + + WorkspaceMemento b(ws, 0); + TSM_ASSERT_THROWS_NOTHING("Should be unlocked, so should have obtained lock without throwing!", b.lock()); + b.unlock(); +} + + + + +}; + +#endif \ No newline at end of file