MeVisLabToolboxReference
MeVisLab/Standard/Sources/ML/MLBase/mlListBase.h
Go to the documentation of this file.
00001 // **InsertLicense** code
00002 //----------------------------------------------------------------------------------
00004 
00009 //
00010 // Defines the following classes:
00011 // - ListBase: An abstract class derived from Base providing methods available
00012 //     for all list classes.
00013 // - ListTemplate: A class template derived from ListBase and std::vector.
00014 //     It implements the persistence functionality of a list.
00015 // - BaseListTemplate: A class template derived from ListTemplate. It should be
00016 //     used for item classes that are subclasses of BaseItem.
00017 // - For class BaseItem see mlBaseItem.h.
00018 //----------------------------------------------------------------------------------
00019 
00020 #ifndef __mlListBase_H
00021 #define __mlListBase_H
00022 
00023 
00024 // ML-includes
00025 #ifndef __mlBaseInit_H
00026 #include "mlBaseInit.h"
00027 #endif
00028 #ifndef __mlModuleIncludes_H
00029 #include "mlModuleIncludes.h"
00030 #endif
00031 #ifndef __mlTreeNode_H
00032 #include "mlTreeNode.h"
00033 #endif
00034 #ifndef __mlStringConversion_H
00035 #include "mlStringConversion.h"
00036 #endif
00037 
00038 
00039 // Local includes
00040 #ifndef __mlListParser_H
00041 #include "mlListParser.h"
00042 #endif
00043 
00044 // Also include BaseItem although it is not needed here; however many derived classes still expect it.
00045 #ifndef __mlBaseItem_H
00046 #include "mlBaseItem.h"
00047 #endif
00048 
00049 // Safe casts.
00050 #ifndef __mlRangeCasts_H
00051 #include "mlRangeCasts.h"
00052 #endif
00053 
00054 ML_START_NAMESPACE
00055 
00056 class BaseItem;
00057 
00058 // ------------------------------------------------------------------
00060 // ------------------------------------------------------------------
00061 
00070 class MLBASEEXPORT ListBase : public Base
00071 {
00072 public:
00073 
00075   ListBase (bool persistance)
00076     : _hasPersistance(persistance),
00077       _actionClass(ActNew),
00078       _actionId(-1),
00079       _actionIndex(-1),
00080       _currentIndex(-1)
00081   {}
00082 
00083 
00085 
00086 
00088   virtual size_t getSize () const = 0;
00089 
00095   virtual BaseItem* getItemAt(MLssize_t /*index*/) { return NULL; };
00096 
00098   virtual const BaseItem* getConstItemAt(MLssize_t /*index*/) const { return NULL; };
00099 
00103   virtual void insertItemAt(MLssize_t /*index*/, const BaseItem* /*item*/) {};
00104 
00108   virtual void modifyItemAt(MLssize_t /*index*/, const BaseItem* /*item*/) {};
00109 
00113   virtual void deleteItemAt(MLssize_t /*index*/) {};
00114 
00118   virtual void selectItemAt(MLssize_t /*index*/) {};
00119 
00123   virtual const RuntimeType* getItemTypeId() const { return NULL; };
00124 
00126   virtual void clearList ()
00127   { setAction(ActNew); }
00128 
00135   virtual ListBase* clone() const { return NULL; };
00136 
00138   virtual ListBase* deepCopy() const { return clone(); };
00139 
00141 
00142 
00150 
00151 
00153   virtual bool hasPersistance () const { return _hasPersistance; }
00154 
00156   virtual void setPersistance (bool persistance) { _hasPersistance = persistance; }
00157 
00159   MLBASEEXPORT friend std::ostream& operator << (std::ostream &s, const ListBase &list);
00160 
00162   virtual void addStateToTree(TreeNode* parent) const;
00163 
00165   ML_SET_ADDSTATE_VERSION(0);
00166 
00168   virtual void readStateFromTree(TreeNode* parent);
00169 
00171 
00172 
00185 
00186 
00188   enum ActionClass
00189        {
00190          ActNone = 0,        
00191          ActUnknown,         
00192          ActNew,             
00193          ActSelect,          
00194 
00195          ActModify,          
00196          ActDelete,          
00197 
00198          ActInsert,          
00199          ActInsertOvw,       
00200 
00201 
00202 
00203          ActNumActions       
00204        };
00205 
00207   static const char *const ActionClassNames[ActNumActions];
00208 
00210   virtual void setAction (ActionClass actionClass, MLssize_t id, MLssize_t index);
00211 
00213   virtual void setAction (ActionClass actionClass)
00214   { setAction(actionClass, -1, -1); }
00215 
00217   virtual void getAction (ActionClass &actionClass, MLssize_t &id, MLssize_t &index) const;
00218 
00220   virtual ActionClass getActionClass () const
00221   { return _actionClass; }
00222 
00224   virtual MLssize_t getActionId () const
00225   { return _actionId; }
00226 
00230   virtual MLssize_t getActionIndex () const
00231   { return _actionIndex; }
00232 
00234   virtual MLssize_t getCurrentIndex () const
00235   { return _currentIndex; }
00236 
00238   virtual bool isModified () const
00239   { return (ActSelect != _actionClass && ActNone != _actionClass); }
00240 
00241 
00243 
00244 
00245 protected:
00246 
00250   char *newString (const std::string &str) const
00251   { return ParserBase::newString(str); }
00252 
00254   void deleteString (char *str) const
00255   { ParserBase::deleteString(str); }
00256 
00258   ListBase &operator = (const ListBase &list);
00259 
00260 private:
00261 
00263   bool _hasPersistance;
00264 
00266   ActionClass _actionClass;
00267 
00269   MLssize_t _actionId;
00270 
00272   MLssize_t _actionIndex;
00273 
00275   MLssize_t _currentIndex;
00276 
00277 
00278   ML_ABSTRACT_CLASS_HEADER(ListBase)
00279 
00280 };
00281 
00282 
00283 
00284 // ------------------------------------------------------------------
00286 // ------------------------------------------------------------------
00287 
00311 template <class T>
00312 class ListTemplate : public ListBase, public std::vector<T>
00313 {
00314 public:
00315 
00318   typedef T itemType;
00319 
00320 
00322 
00323 
00325   ListTemplate () : ListBase(false) {}
00326 
00328   ListTemplate (bool persistance) : ListBase(persistance) {}
00329 
00331 
00332 
00334 
00335 
00337   virtual size_t getSize () const
00338   { using namespace std; return vector<T>::size(); }
00339 
00341   virtual void clearList ()
00342   { ListBase::clearList(); using namespace std; vector<T>::clear(); }
00343 
00344 
00346   ListTemplate<T> &operator = (const ListTemplate<T> &list)
00347   {
00348     using namespace std;
00349 
00350     ListBase::operator =(list);
00351     vector<T>::operator =(list);
00352 
00353     return *this;
00354   }
00355 
00360   virtual ListTemplate<T>* clone() const;
00361 
00363   virtual ListTemplate<T>* deepCopy() const { return clone(); };
00364 
00366 
00367 
00369 
00370 
00373   virtual char *getPersistentState () const;
00374 
00376   virtual void setPersistentState (const char *state);
00377 
00380   virtual void clearPersistentState (char *state) const
00381   { deleteString(state); }
00382 
00384   virtual void addStateToTree(TreeNode* parent) const;
00385 
00387   ML_SET_ADDSTATE_VERSION(2);
00388 
00390   virtual void readStateFromTree(TreeNode* parent);
00391 
00393 
00394 
00395 protected:
00396 
00406 
00407 
00410     //  virtual char *getItemState (iterator /*it*/) { return 0; }
00411   virtual char *getItemState (typename ListTemplate<T>::const_iterator /*it*/) const { return 0; }
00412 
00414     //virtual void setItemState (iterator /*it*/, const char* /*state*/) {}
00415   virtual void setItemState (typename ListTemplate<T>::iterator /*it*/, const char* /*state*/) {}
00416 
00419     //virtual void clearItemState (iterator /*it*/, char *state)
00420   virtual void clearItemState (typename ListTemplate<T>::iterator /*it*/, char *state) const
00421   { deleteString(state); }
00422 
00424 
00425 };
00426 
00427 
00428 
00429 // ------------------------------------------------------------------
00430 // Implementation of ListTemplate
00431 // ------------------------------------------------------------------
00432 
00435 template <class T>
00436 char *ListTemplate<T>::getPersistentState () const
00437 {
00438   using namespace std;
00439 
00440   typename ListTemplate<T>::const_iterator it;
00441   char *itemStr=NULL, *pListStr=NULL, *pItemStr=NULL;
00442   std::string listStr;
00443 
00444   if (hasPersistance())
00445   {
00446     // Start list with an opening bracket
00447     listStr = "[";
00448 
00449     // Iterate through list
00450     for (it = vector<T>::begin(); it != vector<T>::end(); it++)
00451     {
00452       // Separate items by a comma
00453         if (it != vector<T>::begin()){
00454             listStr += ", ";
00455         }
00456 
00457       // Get string representation for item object
00458       itemStr = getItemState(it);
00459       if (itemStr)
00460       {
00461         // Item string needs to be quoted?
00462         if (ListParser::needsQuote(itemStr))
00463         {
00464           // Obtain quoted version of item string and append it to list string
00465           pItemStr = ListParser::quoteString(itemStr);
00466           listStr += pItemStr;
00467           ListParser::deleteString(pItemStr);
00468         }
00469         else
00470           // Append unquoted item string to list string
00471           listStr += itemStr;
00472       }
00473       else
00474         // Empty item string, add "" to list string
00475         listStr += "\"\"";
00476     }
00477 
00478     // End list with a closing bracket
00479     listStr += ']';
00480 
00481     // Create copy of list string on heap
00482     pListStr = newString(listStr);
00483   }
00484 
00485   return pListStr;
00486 }
00487 
00488 
00490 template <class T>
00491 void ListTemplate<T>::setPersistentState (const char *state)
00492 {
00493   ListParser parser;
00494   int parserResult=0;
00495   char *pItemString=NULL;
00496 
00497   if (hasPersistance())
00498   {
00499     // Start with empty list
00500     clearList();
00501 
00502     // Initialize parser
00503     parserResult = parser.init(state);
00504 
00505     while (!parserResult)
00506     {
00507       // Parse next item string
00508       parserResult = parser.nextItemString(pItemString);
00509       if (pItemString && parserResult != ListParser::kEndOfSource)
00510       {
00511         using namespace std;
00512 
00513         // Append new item object at end of list
00514         vector<T>::insert(vector<T>::end(),  T());
00515 
00516         // Restore item object from item string
00517         setItemState(vector<T>::end()-1, pItemString);
00518 
00519         // Dispose item string
00520         ListParser::deleteString(pItemString);
00521       }
00522     }
00523 
00524     // Set list action
00525     setAction(ListBase::ActNew);
00526 
00527     // Print error message to console
00528     if (parserResult > 0 && parserResult != ParserBase::kEmptyString) {
00529       ML_PRINT_ERROR("ListTemplate::setPersistentState()", ML_EMPTY_MESSAGE,
00530                      parser.getErrorMessage(parserResult));
00531     }
00532   }
00533 }
00534 
00535 
00539 template <class T>
00540 void ListTemplate<T>::addStateToTree(TreeNode* parent) const
00541 {
00542   using namespace std;
00543 
00544   //if (!hasPersistance()) return;
00545 
00546   ML_ADDSTATE_VERSION(ListTemplate<T>);
00547 
00548   // add listbase members
00549   ML_ADDSTATE_SUPER(ListBase);
00550 
00551   typename ListTemplate<T>::const_iterator it;
00552 
00553   // write list size always as unsigned 64 bit integer.
00554   parent->addChild(static_cast<MLuint64>(vector<T>::size()), "ListSize");
00555 
00556   // write list items:
00557   TreeNode* items = parent->addChild("ListItems");
00558 
00559   // Iterate through list
00560   for (it = vector<T>::begin(); it != vector<T>::end(); it++)
00561   {
00562     char* state = getItemState(it);
00563     items->addChild(state, "Item");
00564     ML_DELETE_ARRAY(state);
00565   }
00566 
00567 }
00568 
00570 template <class T>
00571 void ListTemplate<T>::readStateFromTree(TreeNode* parent)
00572 {
00573   using namespace std;
00574 
00575   if (!hasPersistance()) { return; }
00576 
00577   int version = parent->getVersion("ListTemplate");
00578 
00579   // Currently supporting version <= 2 only, version 2 is saved by 64 bit systems.
00580   if (version > 2){
00581     // Error, too high version number.
00582     throw TreeNodeException(TNE_UnsupportedClassVersion);
00583   }
00584 
00585   if (version >= 1) {
00586     // ListBase saves its members since version 1:
00587     ML_READSTATE_SUPER(ListBase);
00588   }
00589 
00590   bool endLoop = false;
00591 
00592   clearList();
00593 
00594   // read size if possible
00595   MLuint64 loadedSize = 0;
00596   ML_READCHILD_OPTIONAL(loadedSize, "ListSize", 0);
00597 
00598   #if !defined(ML_IS_64_BIT_SYSTEM)
00599     // Check whether list size is too large for 32 bit systems.
00600     if (loadedSize >= static_cast<MLuint64>(ML_UINT32_MAX)){
00601       ML_PRINT_ERROR("ListTemplate<T>::readStateFromTree",
00602                      ML_OUT_OF_RANGE,
00603                      "The stored ListSize parameter of a ListTemplate is too "
00604                      "large to be handled on 32 bit systems. It is set to 0 to "
00605                      "avoid memory overflows; thus the structure is not loaded "
00606                      "correctly.");
00607       loadedSize = 0;
00608     }
00609   #endif
00610 
00611   // reserve some memory for the list. However, we do really want to rely on the ListSize
00612   // setting and still read until a child is not found.
00613   vector<T>::reserve( static_cast<size_t>(loadedSize) );
00614 
00615   TreeNode* items = parent->readContainerChild("ListItems");
00616 
00617   char* currStr = NULL;
00618   do {
00619     // try to read next child:
00620     if (items->hasChild()) {
00621       items->readChild(currStr);
00622     } else {
00623       // break free from loop
00624       endLoop = true;
00625     }
00626     if (!endLoop) {
00627 
00628       vector<T>::insert(vector<T>::end(), T());
00629 
00630       // Restore item object from item string
00631       setItemState(vector<T>::end()-1, currStr);
00632       items->deleteString(currStr);
00633       currStr = NULL;
00634     }
00635   } while (!endLoop);
00636 
00637   items->deleteString(currStr);
00638 
00639   // Set list action
00640   setAction(ListBase::ActNew);
00641 }
00642 
00643 
00644 
00649 template <class T>
00650 ListTemplate<T>* ListTemplate<T>::clone() const
00651 {
00652   // get runtime type of this instance
00653   const RuntimeType* thisType = this->getTypeId();
00654 
00655   // valid type?
00656   if (!thisType || !thisType->canCreateInstance()) {
00657     // invalid type
00658     return NULL;
00659   }
00660 
00661   ListTemplate<T>* newList = static_cast<ListTemplate<T>*>(thisType->createInstance());
00662   if (!newList) {
00663     // object creation failed
00664     return NULL;
00665   }
00666 
00667   (*newList) = (*this);
00668 
00669   return newList;
00670 }
00671 
00672 
00673 
00674 
00675 
00676 // ------------------------------------------------------------------
00678 // ------------------------------------------------------------------
00679 
00700 template <class T>
00701 class BaseListTemplate : public ListTemplate<T>
00702 {
00703 public:
00704 
00706 
00707 
00709   BaseListTemplate () : ListTemplate<T>(), _nextId(1) {}
00710 
00712   BaseListTemplate (bool persistance) : ListTemplate<T>(persistance), _nextId(1) {}
00713 
00715 
00721   virtual BaseItem* getItemAt(MLssize_t index){
00722     return &(*this)[mlrange_cast<size_t>(index)];
00723   };
00724 
00726   virtual const BaseItem* getConstItemAt(MLssize_t index) const {
00727     return &(*this)[mlrange_cast<size_t>(index)];
00728   };
00729 
00734   virtual void insertItemAt(MLssize_t index, const BaseItem* item) {
00735     if (item && (getItemTypeId() == item->getTypeId())) {
00736       doInsertItem(index, *static_cast<const T*>(item) );
00737     }
00738   };
00739 
00740 
00745   virtual void modifyItemAt(MLssize_t index, const BaseItem* item) {
00746     if (item && (getItemTypeId() == item->getTypeId())) {
00747       doModifyItem(index, *static_cast<const T*>(item) );
00748     }
00749   };
00750 
00755   virtual void deleteItemAt(MLssize_t index) {
00756     doDeleteItem(index);
00757   };
00758 
00763   virtual void selectItemAt(MLssize_t index) {
00764     doSelectItem(index);
00765   };
00766 
00770   virtual const RuntimeType* getItemTypeId() const {
00771     return T::getClassTypeId();
00772   }
00773 
00774 
00776 
00777 
00779   virtual MLssize_t newId () { return _nextId++; }
00780 
00782   virtual void usedId (MLssize_t id)
00783   {
00784       if (id >= _nextId) {
00785         _nextId = id+1;
00786       }
00787   }
00788 
00790   virtual void resetId ()
00791   {
00792     _nextId = 1;
00793     for (typename ListTemplate<T>::iterator it = ListTemplate<T>::begin(); it != ListTemplate<T>::end(); it++){
00794       usedId(it->getId());
00795     }
00796   }
00797 
00799 
00801   virtual void clearList ()
00802   {
00803     ListTemplate<T>::clear();
00804     resetId();
00805   }
00806 
00807 
00816 
00817 
00819   virtual void doDeleteItem (MLssize_t index);
00820 
00823   virtual void doInsertItem (MLssize_t index, const T &item);
00824 
00827   virtual void doModifyItem (MLssize_t index, const T &item);
00828 
00831   virtual void doSelectItem (MLssize_t index);
00832 
00835   virtual void appendItem(const T &item);
00836 
00838   virtual void addStateToTree(TreeNode* parent) const;
00839 
00841 
00845   ML_SET_ADDSTATE_VERSION(1);
00846 
00848   virtual void readStateFromTree(TreeNode* parent);
00849 
00850 
00851 
00853 
00854 
00855 protected:
00856 
00862 
00863 
00866   virtual char *getItemState (typename ListTemplate<T>::const_iterator it) const
00867   { return it->getPersistentState(); }
00868 
00870   virtual void setItemState (typename ListTemplate<T>::iterator it, const char *state)
00871   {
00872     it->setPersistentState(state);
00873     usedId(it->getId());
00874   }
00875 
00878   virtual void clearItemState (typename ListTemplate<T>::iterator it, char *state) const
00879   { it->clearPersistentState(state); }
00880 
00882 
00883 
00884 private:
00885 
00887   MLssize_t _nextId;
00888 
00889 };
00890 
00891 
00892 
00893 
00894 // ------------------------------------------------------------------
00895 // --- Implementation of BaseListTemplate
00896 // ------------------------------------------------------------------
00897 
00899 template <class T>
00900 void BaseListTemplate<T>::doDeleteItem (MLssize_t index)
00901 {
00902   if ((index >= 0) && (index < static_cast<MLssize_t>(ListTemplate<T>::size())) )
00903   {
00904     this->setAction(ListTemplate<T>::ActDelete, (*this)[mlrange_cast<size_t>(index)].getId(), index);
00905     ListTemplate<T>::erase(ListTemplate<T>::begin()+index);
00906   }
00907 }
00908 
00909 
00912 template <class T>
00913 void BaseListTemplate<T>::doInsertItem (MLssize_t index, const T &item)
00914 {
00915   MLssize_t id=0;
00916 
00917   if ((index >= 0) && (index <= mlrange_cast<MLssize_t>(ListTemplate<T>::size())) )
00918   {
00919     ListTemplate<T>::insert(ListTemplate<T>::begin()+index, item);
00920     id = newId();
00921     (*this)[static_cast<size_t>(index)].setId(id);
00922     this->setAction(ListTemplate<T>::ActInsert, id, index);
00923   }
00924 }
00925 
00928 template <class T>
00929 void BaseListTemplate<T>::appendItem(const T &item)
00930 {
00931     doInsertItem(static_cast<MLssize_t>(ListTemplate<T>::size()), item);
00932 }
00933 
00934 
00937 template <class T>
00938 void BaseListTemplate<T>::doModifyItem (MLssize_t index, const T &item)
00939 {
00940   if ((index >= 0) && (index < mlrange_cast<MLssize_t>(ListTemplate<T>::size())) )
00941   {
00942     const size_t idx_size_t = static_cast<size_t>(index);
00943     const MLssize_t id = (*this)[idx_size_t].getId();
00944     (*this)[idx_size_t] = item;
00945     (*this)[idx_size_t].setId(id);
00946     this->setAction(ListTemplate<T>::ActModify, id, index);
00947   }
00948 }
00949 
00950 
00953 template <class T>
00954 void BaseListTemplate<T>::doSelectItem (MLssize_t index)
00955 {
00956   if ((index >= 0) && (index < mlrange_cast<MLssize_t>(ListTemplate<T>::size())) )
00957   {
00958     this->setAction(ListTemplate<T>::ActSelect, (*this)[static_cast<size_t>(index)].getId(), index);
00959   }
00960 }
00961 
00962 
00966 template <class T>
00967 void BaseListTemplate<T>::addStateToTree(TreeNode* parent) const
00968 {
00969   ML_ADDSTATE_VERSION(BaseListTemplate<T>);
00970 
00971   // add ListBase members
00972   ML_ADDSTATE_SUPER(ListBase);
00973 
00974   typename BaseListTemplate<T>::const_iterator it;
00975   MLuint64 i = 0;
00976 
00977   // write list size
00978   parent->addChild(static_cast<MLuint64>(ListTemplate<T>::size()), "ListSize");
00979 
00980   TreeNode* items = parent->addChild("ListItems");
00981 
00982   // Iterate through list
00983   for (it = ListTemplate<T>::begin(); it != ListTemplate<T>::end(); it++, i++)
00984   {
00985     items->addChild(&(*it), "Item", false);
00986   }
00987 
00988 }
00989 
00991 template <class T>
00992 void BaseListTemplate<T>::readStateFromTree(TreeNode* parent)
00993 {
00994   int version = parent->getVersion("BaseListTemplate");
00995 
00996   // Currently supporting version <= 2 only, version 2 is 64 bit version.
00997   if (version > 2) {
00998     throw TreeNodeException(TNE_UnsupportedClassVersion);
00999   }
01000 
01001   if (version >= 1) {
01002     // ListBase saves its members since version 1:
01003     ML_READSTATE_SUPER(ListBase);
01004   }
01005 
01006   bool endLoop = false;
01007 
01008   clearList(); // includes _nextId = 1;
01009 
01010   // read size if possible
01011   MLuint64 loadedSize = 0;
01012   ML_READCHILD_OPTIONAL(loadedSize, "ListSize", 0);
01013 
01014   #if !defined(ML_IS_64_BIT_SYSTEM)
01015     // Check whether list size is too large for 32 bit systems.
01016     if (loadedSize >= static_cast<MLuint64>(ML_UINT32_MAX)){
01017       ML_PRINT_ERROR("BaseListTemplate<T>::readStateFromTree",
01018                      ML_OUT_OF_RANGE,
01019                      "The stored ListSize parameter of a BaseListTemplate is too "
01020                      "large to be handled on 32 bit systems. It is set to 0 to "
01021                      "avoid memory overflows; thus the structure is not loaded "
01022                      "correctly.");
01023       loadedSize = 0;
01024     }
01025   #endif
01026 
01027   // reserve some memory for the list. However, we do not really want to rely on the ListSize
01028   // setting and still read until a child is not found.
01029   ListTemplate<T>::reserve( static_cast<size_t>(loadedSize) );
01030 
01031   TreeNode* items = parent->readContainerChild("ListItems");
01032 
01033   if (items) do {
01034     // try to read next child:
01035     if (items->hasChild()) {
01036       ListTemplate<T>::insert(ListTemplate<T>::end(), T());
01037       items->readChild(*(ListTemplate<T>::end()-1));
01038     } else {
01039       // break free from loop
01040       endLoop = true;
01041     }
01042     if (ListTemplate<T>::size() > 0){
01043         // update _nextId:
01044         _nextId = ML_MAX(_nextId, (ListTemplate<T>::end()-1)->getId() + 1);
01045     } else {
01046         endLoop = true;
01047     }
01048   } while (!endLoop);
01049 
01050   // Set list action
01051   this->setAction(ListTemplate<T>::ActNew);
01052 }
01053 
01054 
01055 ML_END_NAMESPACE
01056 
01057 
01058 #endif // __mlListBase_H
01059