MeVisLabToolboxReference
|
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