NptMap.h

00001 /*****************************************************************
00002 |
00003 |   Neptune - Maps
00004 |
00005 |   (c) 2001-2006 Gilles Boccon-Gibod
00006 |   Author: Gilles Boccon-Gibod (bok@bok.net)
00007 |
00008 ****************************************************************/
00009 
00010 #ifndef _NPT_MAP_H_
00011 #define _NPT_MAP_H_
00012 
00013 /*----------------------------------------------------------------------
00014 |   includes
00015 +---------------------------------------------------------------------*/
00016 #include "NptTypes.h"
00017 #include "NptResults.h"
00018 #include "NptList.h"
00019 
00020 /*----------------------------------------------------------------------
00021 |   NPT_Map
00022 +---------------------------------------------------------------------*/
00023 template <typename K, typename V> 
00024 class NPT_Map 
00025 {
00026 public:
00027     // types
00028     class Entry {
00029     public:
00030         // constructor
00031         Entry(const K& key, const V& value) : m_Key(key), m_Value(value) {}
00032         Entry(const K& key) : m_Key(key) {}
00033         
00034         // accessors
00035         const K& GetKey()   const { return m_Key;   }
00036         const V& GetValue() const { return m_Value; }
00037 
00038         // operators 
00039         bool operator==(const Entry& other) const {
00040             return m_Key == other.m_Key && m_Value == other.m_Value;
00041         }
00042 
00043     protected:
00044         // methods
00045         void SetValue(const V& value) { m_Value = value; }
00046 
00047         // members
00048         K m_Key;
00049         V m_Value;
00050 
00051         // friends
00052         friend class NPT_Map<K,V>;
00053     };
00054 
00055     class EntryValueDeleter {
00056     public:
00057         void operator()(Entry* entry) const {
00058             delete entry->GetValue();
00059         }
00060     };
00061 
00062     // constructors
00063     NPT_Map<K,V>() {}
00064     NPT_Map<K,V>(const NPT_Map<K,V>& copy);
00065 
00066     // destructor
00067     ~NPT_Map<K,V>();
00068 
00069     // methods
00070     NPT_Result   Put(const K& key, const V& value);
00071     NPT_Result   Get(const K& key, V*& value) const;
00072     bool         HasKey(const K& key) const { return GetEntry(key) != NULL; }
00073     bool         HasValue(const V& value) const;
00074     NPT_Result   Erase(const K& key);
00075     NPT_Cardinal GetEntryCount() const         { return m_Entries.GetItemCount(); }
00076     const NPT_List<Entry*>& GetEntries() const { return m_Entries; }
00077     NPT_Result   Clear();
00078 
00079     // operators
00080     V&                  operator[](const K& key);
00081     const NPT_Map<K,V>& operator=(const NPT_Map<K,V>& copy);
00082     bool                operator==(const NPT_Map<K,V>& other) const;
00083     bool                operator!=(const NPT_Map<K,V>& other) const;
00084 
00085 private:
00086     // types
00087     typedef typename NPT_List<Entry*>::Iterator ListIterator;
00088 
00089     // methods
00090     Entry* GetEntry(const K& key) const;
00091 
00092     // members
00093     NPT_List<Entry*> m_Entries;
00094 };
00095 
00096 /*----------------------------------------------------------------------
00097 |   NPT_Map<K,V>::NPT_Map<K,V>
00098 +---------------------------------------------------------------------*/
00099 template <typename K, typename V>
00100 NPT_Map<K,V>::NPT_Map(const NPT_Map<K,V>& copy)
00101 {
00102     *this = copy;
00103 }
00104 
00105 /*----------------------------------------------------------------------
00106 |   NPT_Map<K,V>::~NPT_Map<K,V>
00107 +---------------------------------------------------------------------*/
00108 template <typename K, typename V>
00109 inline
00110 NPT_Map<K,V>::~NPT_Map()
00111 {
00112     // call Clear to ensure we delete all entry objects
00113     Clear();
00114 }
00115 
00116 /*----------------------------------------------------------------------
00117 |   NPT_Map<K,V>::Clear
00118 +---------------------------------------------------------------------*/
00119 template <typename K, typename V>
00120 inline
00121 NPT_Result
00122 NPT_Map<K,V>::Clear()
00123 {
00124     m_Entries.Apply(NPT_ObjectDeleter<Entry>());
00125     m_Entries.Clear();
00126 
00127     return NPT_SUCCESS;
00128 }
00129 
00130 /*----------------------------------------------------------------------
00131 |   NPT_Map<K,V>::GetEntry
00132 +---------------------------------------------------------------------*/
00133 template <typename K, typename V>
00134 typename NPT_Map<K,V>::Entry*
00135 NPT_Map<K,V>::GetEntry(const K& key) const
00136 {
00137     typename NPT_List<Entry*>::Iterator entry = m_Entries.GetFirstItem();
00138     while (entry) {
00139         if ((*entry)->GetKey() == key) {
00140             return *entry;
00141         }
00142         ++entry;
00143     }
00144 
00145     return NULL;
00146 }
00147 
00148 /*----------------------------------------------------------------------
00149 |   NPT_Map<K,V>::Put
00150 +---------------------------------------------------------------------*/
00151 template <typename K, typename V>
00152 inline
00153 NPT_Result
00154 NPT_Map<K,V>::Put(const K& key, const V& value)
00155 {
00156     Entry* entry = GetEntry(key);
00157     if (entry == NULL) {
00158         // no existing entry for that key, create one
00159         m_Entries.Add(new Entry(key, value));
00160     } else {
00161         // replace the existing entry for that key
00162         entry->SetValue(value);
00163     }
00164 
00165     return NPT_SUCCESS;
00166 }
00167 
00168 /*----------------------------------------------------------------------
00169 |   NPT_Map<K,V>::Get
00170 +---------------------------------------------------------------------*/
00171 template <typename K, typename V>
00172 inline
00173 NPT_Result
00174 NPT_Map<K,V>::Get(const K& key, V*& value) const
00175 {
00176     Entry* entry = GetEntry(key);
00177     if (entry == NULL) {
00178         // no existing entry for that key
00179         value = NULL;
00180         return NPT_ERROR_NO_SUCH_ITEM;
00181     } else {
00182         // found an entry with that key
00183         value = &entry->m_Value;
00184         return NPT_SUCCESS;
00185     }
00186 }
00187 
00188 /*----------------------------------------------------------------------
00189 |   NPT_Map<K,V>::HasValue
00190 +---------------------------------------------------------------------*/
00191 template <typename K, typename V>
00192 bool
00193 NPT_Map<K,V>::HasValue(const V& value) const
00194 {
00195     ListIterator entry = m_Entries.GetFirstItem();
00196     while (entry) {
00197         if (value == (*entry)->m_Value) {
00198             return true;
00199         }
00200         ++entry;
00201     }
00202 
00203     return false;
00204 }
00205 
00206 /*----------------------------------------------------------------------
00207 |   NPT_Map<K,V>::operator=
00208 +---------------------------------------------------------------------*/
00209 template <typename K, typename V>
00210 const NPT_Map<K,V>&
00211 NPT_Map<K,V>::operator=(const NPT_Map<K,V>& copy)
00212 {
00213     // do nothing if we're assigning to ourselves
00214     if (this == &copy) return copy;
00215 
00216     // destroy all entries
00217     Clear();
00218 
00219     // copy all entries one by one
00220     ListIterator entry = copy.m_Entries.GetFirstItem();
00221     while (entry) {
00222         m_Entries.Add(new Entry((*entry)->GetKey(), (*entry)->GetValue()));
00223         ++entry;
00224     }
00225 
00226     return *this;
00227 }
00228 
00229 /*----------------------------------------------------------------------
00230 |   NPT_Map<K,V>::Erase
00231 +---------------------------------------------------------------------*/
00232 template <typename K, typename V>
00233 inline
00234 NPT_Result
00235 NPT_Map<K,V>::Erase(const K& key)
00236 {
00237     ListIterator entry = m_Entries.GetFirstItem();
00238     while (entry) {
00239         if ((*entry)->GetKey() == key) {
00240             delete *entry; // do this before removing the entry from the
00241                            // list, because Erase() will invalidate the
00242                            // iterator item
00243             m_Entries.Erase(entry);
00244             return NPT_SUCCESS;
00245         }
00246         ++entry;
00247     }
00248 
00249     return NPT_ERROR_NO_SUCH_ITEM;
00250 }
00251 
00252 /*----------------------------------------------------------------------
00253 |   NPT_Map<K,V>::operator==
00254 +---------------------------------------------------------------------*/
00255 template <typename K, typename V>
00256 bool
00257 NPT_Map<K,V>::operator==(const NPT_Map<K,V>& other) const
00258 {
00259     // quick test
00260     if (m_Entries.GetItemCount() != other.m_Entries.GetItemCount()) return false;
00261 
00262     // compare all entries to all other entries
00263     ListIterator entry = m_Entries.GetFirstItem();
00264     while (entry) {
00265         V* value;
00266         if (NPT_SUCCEEDED(other.Get((*entry)->m_Key, value))) {
00267             // the other map has an entry for this key, check the value
00268             if (!(*value == (*entry)->m_Value)) return false;
00269         } else {
00270             // the other map does not have an entry for this key
00271             return false;
00272         }
00273         ++entry;
00274     }
00275 
00276     return true;
00277 }
00278 
00279 /*----------------------------------------------------------------------
00280 |   NPT_Map<K,V>::operator!=
00281 +---------------------------------------------------------------------*/
00282 template <typename K, typename V>
00283 inline
00284 bool
00285 NPT_Map<K,V>::operator!=(const NPT_Map<K,V>& other) const
00286 {
00287     return !(*this == other);
00288 }
00289 
00290 /*----------------------------------------------------------------------
00291 |   NPT_Map<K,V>::operator[]
00292 +---------------------------------------------------------------------*/
00293 template <typename K, typename V>
00294 inline
00295 V&
00296 NPT_Map<K,V>::operator[](const K& key)
00297 {
00298     Entry* entry = GetEntry(key);
00299     if (entry == NULL) {
00300         // create a new "default" entry for this key
00301         entry = new Entry(key);
00302         m_Entries.Add(entry);
00303     }
00304      
00305     return entry->m_Value;
00306 }
00307 
00308 #endif // _NPT_MAP_H_