FDO API Reference Feature Data Objects

IdentifierCollection.h

Go to the documentation of this file.
00001 #ifndef _IDENTIFIERCOLLECTION_H_
00002 #define _IDENTIFIERCOLLECTION_H_
00003 // 
00004 
00005 //
00006 // Copyright (C) 2004-2006  Autodesk, Inc.
00007 // 
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of version 2.1 of the GNU Lesser
00010 // General Public License as published by the Free Software Foundation.
00011 // 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 // Lesser General Public License for more details.
00016 // 
00017 // You should have received a copy of the GNU Lesser General Public
00018 // License along with this library; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 //
00021 
00022 #ifdef _WIN32
00023 #pragma once
00024 #endif
00025 
00026 #include <FdoStd.h>
00027 #include <Fdo/Expression/Identifier.h>
00028 #include <Fdo/Commands/CommandException.h>
00029 
00030 /// \brief
00031 /// The FdoIdentifierCollection class represents a collection of FdoIdentifier objects.
00032 class FdoIdentifierCollection : public FdoCollection<FdoIdentifier, FdoCommandException>
00033 {
00034 /// \cond DOXYGEN-IGNORE
00035 protected:
00036     virtual void Dispose();
00037 /// \endcond
00038 
00039 public:
00040     /// \brief
00041     /// Constructs a default empty instance of an FdoIdentifierCollection.
00042     /// 
00043     /// \return
00044     /// Returns nothing
00045     /// 
00046     FDO_API static FdoIdentifierCollection* Create();
00047 
00048 
00049     /// \brief
00050     /// Gets the item in the collection at the specified index. Throws an invalid argument exception if the index is out of range.
00051     /// 
00052     /// \param index 
00053     /// Input index
00054     /// 
00055     /// \return
00056     /// Returns the item in the collection at the specified index
00057     /// 
00058     FDO_API FdoIdentifier* GetItem(FdoInt32 index)
00059     {
00060         return FdoCollection<FdoIdentifier, FdoCommandException>::GetItem(index);
00061     }
00062 
00063     /// \brief
00064     /// Gets the item in the collection with the specified name. Throws an exception if the item is not found.
00065     /// 
00066     /// \param name 
00067     /// Input item name
00068     /// 
00069     /// \return
00070     /// Returns the item in the collection with the specified name
00071     /// 
00072     FDO_API FdoIdentifier* GetItem(const wchar_t* name)
00073     {
00074         FdoIdentifier* item = FindItem( name );
00075         if ( !item ) 
00076             throw FdoCommandException::Create(
00077                 FdoException::NLSGetMessage(
00078                     FDO_NLSID(FDO_38_ITEMNOTFOUND),
00079                     name
00080                 )
00081             );
00082 
00083         return(item);
00084     }
00085 
00086 
00087     /// \brief
00088     /// Finds the item in the collection with the specified name.
00089     /// 
00090     /// \param name 
00091     /// Input item name
00092     /// 
00093     /// \return
00094     /// Returns the item in the collection with the specified name.
00095     /// Returns NULL if the item was not found.
00096     /// 
00097     FDO_API FdoIdentifier* FindItem(const wchar_t* name)
00098     {
00099     // trigger the building of a map when the collection reaches the threshold size.
00100         ((FdoIdentifierCollection*) this)->InitMap();
00101 
00102         FdoIdentifier* obj = NULL;
00103 
00104         if ( mpNameMap ) {
00105     // Accessing the map is faster for large collections, so use it if built.
00106             obj = GetMap(name);
00107 
00108     // If the object name can't be modified then we're done.
00109     // Otherwise, there's a chance the object name was modified,
00110     // meaning that it can be in the collection but not the map,
00111     // or in the wrong place in the map.
00112     /*  FdoIdentifier supports SetText() so we have to assume the text might have changed
00113             if ( (obj != NULL) && !obj->CanSetName() )
00114                 return(obj);
00115     */
00116 
00117     // If the found object's name is the same as the given name
00118     // then we're done. Otherwise, this object's name has changed
00119     // and a linear search is needed to find the requested object.
00120             if ( (obj != NULL) && (Compare(obj->GetText(), name) != 0) )
00121                 FDO_SAFE_RELEASE( obj );
00122         }
00123 
00124         if ( obj == NULL ) {
00125     // No map so do linear search.
00126             for ( FdoInt32 i = 0; i < FdoCollection<FdoIdentifier, FdoCommandException>::GetCount(); i++ ) {
00127                 FdoIdentifier* obj = GetItem(i);
00128 
00129                 if ( Compare(name, obj->GetText()) == 0 )
00130                     return(obj);
00131 
00132                 FDO_SAFE_RELEASE(obj);
00133             }
00134         }
00135 
00136         return (obj);
00137     }
00138 
00139     /// \brief
00140     /// Sets the item in the collection at the specified index to the specified value. Throws an invalid argument exception if the index is out of range.
00141     /// 
00142     /// \param index 
00143     /// Input index
00144     /// \param value 
00145     /// Input value
00146     /// 
00147     /// \return
00148     /// Returns nothing
00149     /// 
00150     virtual void SetItem(FdoInt32 index, FdoIdentifier* value)
00151     {
00152         CheckDuplicate( value, index );
00153 
00154     // Remove the old item from the map 
00155         if ( mpNameMap ) 
00156             RemoveMapAt(index);
00157 
00158     // Add the new item to the map
00159         if ( mpNameMap && value ) 
00160             InsertMap( value );
00161 
00162     // Set the new item in the collection.
00163         FdoCollection<FdoIdentifier, FdoCommandException>::SetItem(index, value);
00164     }
00165 
00166     /// \brief
00167     /// Adds the specified item to the end of the collection. Returns the index of the newly added item.
00168     /// 
00169     /// \param value 
00170     /// Input value
00171     /// 
00172     /// \return
00173     /// Returns the index of the newly added item
00174     /// 
00175     virtual FdoInt32 Add( FdoIdentifier* value)
00176     {
00177         CheckDuplicate( value, -1 );
00178 
00179     // Insert the new item in the map
00180         if ( mpNameMap && value ) {
00181             InsertMap(value);
00182         }
00183 
00184     // add it to the list.
00185         return( FdoCollection<FdoIdentifier, FdoCommandException>::Add(value) );
00186     }
00187 
00188     /// \brief
00189     /// Inserts the specified item at the specified index within the collection. 
00190     /// Items following the insertion point are moved down to accommodate the new item. 
00191     /// Throws an invalid argument exception if the specified index is out of range.
00192     /// 
00193     /// \param item 
00194     /// Input index
00195     /// \param value 
00196     /// Input value
00197     /// 
00198     /// \return
00199     /// Returns nothing
00200     /// 
00201     virtual void Insert( FdoInt32 item, FdoIdentifier* value)
00202     {
00203         CheckDuplicate( value, -1 );
00204 
00205     // Insert the new item in the map
00206         if ( mpNameMap ) {
00207             InsertMap(value);
00208         }
00209 
00210     // Insert it in the list
00211         return( FdoCollection<FdoIdentifier, FdoCommandException>::Insert(item, value) );
00212     }
00213 
00214     /// \brief
00215     /// Removes all items from the collection.
00216     /// 
00217     /// \return
00218     /// Returns nothing
00219     /// 
00220     virtual void Clear()
00221     {
00222     // Clear the map
00223         if (mpNameMap ) {
00224             delete mpNameMap;
00225             mpNameMap = NULL;
00226         }
00227 
00228     // Clear the list
00229         FdoCollection<FdoIdentifier, FdoCommandException>::Clear();
00230     }
00231 
00232     /// \brief
00233     /// Removes the specified item from the collection. Throws an invalid argument exception if the item does not exist within the collection.
00234     /// 
00235     /// \param value 
00236     /// Input value
00237     /// 
00238     /// \return
00239     /// Returns nothing
00240     /// 
00241     virtual void Remove(const FdoIdentifier* value)
00242     {
00243     // Remove the item from the map.
00244         if ( mpNameMap ) 
00245             RemoveMap( value );
00246 
00247     // Remove it from the list
00248         FdoCollection<FdoIdentifier, FdoCommandException>::Remove(value);
00249     }
00250 
00251     /// \brief
00252     /// Removes the specified item from the collection. Throws an invalid argument exception if the item does not exist within the collection.
00253     /// 
00254     /// \param index 
00255     /// Input index
00256     /// 
00257     /// \return
00258     /// Returns nothing
00259     /// 
00260     virtual void RemoveAt(FdoInt32 index)
00261     {
00262     // Remove the item from the map.
00263         if ( mpNameMap ) 
00264             RemoveMapAt(index);
00265 
00266     // Remove it from the list
00267         FdoCollection<FdoIdentifier, FdoCommandException>::RemoveAt(index);
00268     }
00269 
00270     /// \brief
00271     /// Returns true if the collection contains the specified item, false otherwise.
00272     /// 
00273     /// \param value 
00274     /// Input value
00275     /// 
00276     /// \return
00277     /// Returns true if the collection contains the specified item, false otherwise
00278     /// 
00279     virtual bool Contains(const FdoIdentifier* value)
00280     {
00281     // trigger the building of a map when the collection reaches the threshold size.
00282         ((FdoIdentifierCollection*) this)->InitMap();
00283 
00284         if (mpNameMap )
00285         {
00286     // If map is built, use it since it is faster. 
00287             FdoPtr <FdoIDisposable> temp = GetMap (((FdoIdentifier*)value)->GetText());
00288             bool ret = (temp != NULL);
00289             return (ret);
00290         }
00291         else // Otherwise, linear search
00292         {
00293             FdoString * valueName = ((FdoIdentifier*)value)->GetText();
00294             FdoInt32 count = FdoCollection<FdoIdentifier, FdoCommandException>::GetCount();
00295             bool ret = false;
00296             for (FdoInt32 i = 0; !ret && i < count; i++)
00297             {
00298                 FdoPtr<FdoIdentifier> item = GetItem(i);
00299                 FdoString * itemName = item->GetText();
00300                 ret = (Compare(itemName, valueName)==0);
00301             }
00302             return ret;
00303         }
00304     }
00305    
00306     /// \brief
00307     /// Returns true if the collection contains the specified item, false otherwise.
00308     /// 
00309     /// \param name 
00310     /// Input the item name
00311     /// 
00312     /// \return
00313     /// Returns true if the collection contains the specified item, false otherwise
00314     /// 
00315     virtual bool Contains(FdoString* name)
00316     {
00317         FdoIdentifier* item = FindItem(name);
00318         bool found = (item != NULL);
00319 
00320         FDO_SAFE_RELEASE(item);
00321 
00322         return(found);
00323     }
00324 
00325     /// \brief
00326     /// Returns the index of the specified item in the collection or -1 if the item does not exist.
00327     /// 
00328     /// \param value 
00329     /// Input value
00330     /// 
00331     /// \return
00332     /// Returns the index of the specified item in the collection or -1 if the item does not exist
00333     /// 
00334     virtual FdoInt32 IndexOf(const FdoIdentifier* value)
00335     {
00336         return(FdoCollection<FdoIdentifier, FdoCommandException>::IndexOf(value));
00337     }
00338    
00339     /// \brief
00340     /// Returns the index of the specified item (by name) in the collection or -1 if the item does not exist.
00341     /// 
00342     /// \param name 
00343     /// Input the item name
00344     /// 
00345     /// \return
00346     /// Returns the index of the specified item in the collection or -1 if the item does not exist
00347     /// 
00348     virtual FdoInt32 IndexOf(FdoString* name)
00349     {
00350         if (name == NULL)
00351             throw FdoCommandException::Create(FdoException::NLSGetMessage(FDO_NLSID(FDO_2_BADPARAMETER)));
00352 
00353         FdoInt32    size = FdoCollection<FdoIdentifier, FdoCommandException>::GetCount();
00354         for (FdoInt32 i = 0; i < size; i++)
00355         {
00356             FdoPtr<FdoIdentifier> pitem = GetItem(i);
00357             if (pitem != NULL && pitem->GetText() != (FdoString*) NULL && Compare(name, pitem->GetText()) == 0) {
00358                 return i;
00359             }
00360         }
00361 
00362         return(-1);
00363     }
00364 
00365 protected:
00366     FdoIdentifierCollection( bool caseSensitive = true )
00367     {
00368         mbCaseSensitive = caseSensitive;
00369         mpNameMap = NULL;
00370     }
00371 
00372     virtual ~FdoIdentifierCollection(void)
00373     {
00374         if (mpNameMap ) 
00375             delete mpNameMap;
00376     }
00377 
00378 /// \cond DOXYGEN-IGNORE
00379     int Compare( FdoString* str1, FdoString* str2 ) const
00380     {
00381         if ( mbCaseSensitive )
00382             return ( wcscmp(str1, str2) );
00383 
00384     // Try case-insensitive comparison.
00385 #ifdef _WIN32
00386         return ( _wcsicmp(str1, str2) );
00387 #else
00388         return ( wcscasecmp(str1, str2) );
00389 #endif
00390     }
00391 
00392     void CheckDuplicate( FdoIdentifier* item, FdoInt32 index )
00393     {
00394         FdoPtr<FdoIdentifier> foundItem1 = FindItem( item->GetText() );
00395         FdoPtr<FdoIdentifier> foundItem2;
00396 
00397         if ( index >= 0 ) {
00398             foundItem2 = GetItem(index);
00399         }
00400 
00401         if ( (foundItem1 !=NULL) && (foundItem1.p != foundItem2.p ) ) { 
00402             throw FdoCommandException::Create(
00403                 FdoException::NLSGetMessage(
00404                     FDO_NLSID(FDO_45_ITEMINCOLLECTION),
00405                     (FdoString*) item->GetText()
00406                 )
00407             );
00408         }
00409     }
00410 /// \endcond
00411 
00412 private:
00413     void InitMap()
00414     {
00415     // Build the map if not already built and the collection has hit the threshold
00416         if ( !mpNameMap && ( FdoCollection<FdoIdentifier, FdoCommandException>::GetCount() > FDO_COLL_MAP_THRESHOLD ) ) {
00417             mpNameMap = new std::map<FdoStringP,FdoIdentifier*>();
00418 
00419     // Put all the current elements into the map
00420             for ( FdoInt32 i = (FdoCollection<FdoIdentifier, FdoCommandException>::GetCount() - 1); i >= 0; i-- ) 
00421                 InsertMap( FdoPtr<FdoIdentifier>(GetItem(i)) );
00422         }
00423     }
00424 
00425     void InsertMap( FdoIdentifier* value ) const
00426     {
00427     // Add an element to the map. Elements are keyed by name, which may or may not be case sensitive.
00428     // Case insensitive names are stored in lower case.
00429         if ( mbCaseSensitive ) 
00430             mpNameMap->insert( std::pair<FdoStringP,FdoIdentifier*> ( value->GetText(), value ) );
00431         else
00432             mpNameMap->insert( std::pair<FdoStringP,FdoIdentifier*> ( FdoStringP(value->GetText()).Lower(), value ) );            
00433     }
00434 
00435     // Remove the element at the specified index, from the map
00436     void RemoveMapAt( FdoInt32 index )
00437     {
00438     // Remove the old item from the map 
00439         FdoIdentifier* pItem = FdoCollection<FdoIdentifier, FdoCommandException>::GetItem(index);
00440 
00441         if ( pItem ) {
00442             RemoveMap( pItem );
00443             pItem->Release();
00444         }
00445     }
00446 
00447     // Remove the given element from the map.
00448     void RemoveMap( const FdoIdentifier* value )
00449     {
00450     // handle the current case sensitivity of the element name.
00451         if ( mbCaseSensitive ) 
00452             mpNameMap->erase( FdoStringP( ((FdoIdentifier*)value)->GetText() ) );
00453         else
00454             mpNameMap->erase( FdoStringP( ((FdoIdentifier*)value)->GetText() ).Lower() );            
00455     }
00456 
00457     // Get the named element from the map. Returns NULL if element not in map.
00458     FdoIdentifier* GetMap( const wchar_t* name ) const
00459     {
00460         FdoIdentifier* pItem = NULL;
00461 
00462         /*typename*/ std::map <FdoStringP,FdoIdentifier*> :: const_iterator iter;
00463 
00464         if ( mbCaseSensitive )
00465             iter = mpNameMap->find( FdoStringP(name) );
00466         else 
00467     // Case sensitive names are stored in lower case.
00468             iter = mpNameMap->find( FdoStringP(name).Lower() );
00469 
00470         if ( iter != mpNameMap->end() ) { 
00471             pItem = (FdoIdentifier*) iter->second;
00472             FDO_SAFE_ADDREF(pItem);
00473         }
00474 
00475         return( pItem );
00476     }
00477 
00478     bool mbCaseSensitive;
00479 
00480     // A map keyed by name, to help performance of large collections.
00481     std::map<FdoStringP,FdoIdentifier*> *mpNameMap;
00482 
00483 };
00484 #endif
00485 

Comments or suggestions? Send us feedback.