diff --git a/qse/include/qse/cmn/HashList.hpp b/qse/include/qse/cmn/HashList.hpp index 197530e4..994ecdcb 100644 --- a/qse/include/qse/cmn/HashList.hpp +++ b/qse/include/qse/cmn/HashList.hpp @@ -72,6 +72,10 @@ public: typedef typename DatumList::Node Node; typedef HashList SelfType; + typedef HashListHasher DefaultHasher; + typedef HashListComparator DefaultComparator; + typedef HashListResizer DefaultResizer; + HashList ( Mmgr* mmgr = QSE_NULL, qse_size_t node_capacity = 10, @@ -221,7 +225,46 @@ public: return *this; } + bool isEmpty () const + { + return this->datum_list->isEmpty(); + } + + Node* getHeadNode () const + { + return this->datum_list->getHeadNode(); + } + + Node* getTaileNode () const + { + return this->datum_list->getTailNode(); + } + protected: + Node* find_node (const T& datum) const + { + qse_size_t hc, head, tail; + Node* np; + + hc = this->hasher(datum) % this->node_capacity; + head = hc << 1; tail = head + 1; + + np = this->nodes[head]; + if (np) + { + do + { + T& t = np->value; + if (this->comparator(datum, t)) return np; + if (np == this->nodes[tail]) break; + np = np->getNextNode (); + } + while (1); + } + + return QSE_NULL; + } + Node* insert_value (const T& datum, bool overwrite = true) { qse_size_t hc, head, tail; @@ -269,46 +312,10 @@ protected: return this->nodes[head]; } -public: - Node* insert (const T& datum) - { - return this->insert_value (datum, false); - } - - Node* upsert (const T& datum) - { - return this->insert_value (datum, true); - } - -protected: - const Node* find_node (const T& datum) const - { - qse_size_t hc, head, tail; - Node* np; - - hc = this->hasher(datum) % this->node_capacity; - head = hc << 1; tail = head + 1; - - np = this->nodes[head]; - if (np) - { - do - { - T& t = np->value; - if (datum == t) return np; - if (np == this->nodes[tail]) break; - np = np->getNextNode (); - } - while (1); - } - - return QSE_NULL; - } - public: Node* findNode (const T& datum) { - return (Node*)this->find_node (datum); + return this->find_node (datum); } const Node* findNode (const T& datum) const @@ -330,14 +337,37 @@ public: return &b->value; } - bool isEmpty () const + /// The search() function returns the pointer to the existing node + /// containing the equal value to \a datum. If no node is found, it + /// return #QSE_NULL. + Node* search (const T& datum) { - return this->datum_list->isEmpty(); + return this->find_node (datum); } - bool contains (const T& datum) const + /// The search() function returns the pointer to the existing node + /// containing the equal value to \a datum. If no node is found, it + /// return #QSE_NULL. + const Node* search (const T& datum) const { - return this->findNode (datum) != QSE_NULL; + return this->find_node (datum); + } + + Node* insert (const T& datum) + { + return this->insert_value (datum, false); + } + + Node* update (const T& datum) + { + Node* node = this->find_node (datum); + if (node) node->value = datum; + return node; + } + + Node* upsert (const T& datum) + { + return this->insert_value (datum, true); } int remove (const T& datum) @@ -392,16 +422,6 @@ public: if (this->datum_list) this->datum_list->clear (); } - Node* getHeadNode () const - { - return this->datum_list->getHeadNode(); - } - - Node* getTaileNode () const - { - return this->datum_list->getTailNode(); - } - typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); void traverse (TraverseCallback callback, Node* start) @@ -434,13 +454,13 @@ public: protected: mutable qse_size_t node_capacity; - mutable Node** nodes; + mutable Node** nodes; mutable DatumList* datum_list; mutable qse_size_t threshold; - qse_size_t load_factor; - HASHER hasher; - COMPARATOR comparator; - RESIZER resizer; + qse_size_t load_factor; + HASHER hasher; + COMPARATOR comparator; + RESIZER resizer; void rehash () { diff --git a/qse/include/qse/cmn/HashTable.hpp b/qse/include/qse/cmn/HashTable.hpp index dd80e9ff..cc8404f2 100644 --- a/qse/include/qse/cmn/HashTable.hpp +++ b/qse/include/qse/cmn/HashTable.hpp @@ -72,8 +72,13 @@ class HashTable: public Mmged public: typedef Couple Pair; typedef LinkedList Bucket; + typedef typename LinkedList::Node BucketNode; typedef HashTable SelfType; + typedef HashTableHasher DefaultHasher; + typedef HashTableComparator DefaultComparator; + typedef HashTableResizer DefaultResizer; + protected: Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs) const { @@ -84,7 +89,7 @@ protected: b = (Bucket**) mm->callocate (QSE_SIZEOF(*b) * bs); for (qse_size_t i = 0; i < bs; i++) { - b[i] = new(mm) Bucket (mm); + b[i] = new(mm) Bucket (mm, this->bucket_mpb_size); } } catch (...) @@ -124,13 +129,14 @@ protected: } public: - HashTable (Mmgr* mmgr, qse_size_t bucket_size = 10, qse_size_t load_factor = 75): Mmged(mmgr) + HashTable (Mmgr* mmgr, qse_size_t bucket_size = 10, qse_size_t load_factor = 75, qse_size_t bucket_mpb_size = 0): Mmged(mmgr) { this->buckets = this->allocate_bucket (this->getMmgr(), bucket_size); this->bucket_size = bucket_size; this->pair_count = 0; this->load_factor = load_factor; this->threshold = bucket_size * load_factor / 100; + this->bucket_mpb_size = bucket_mpb_size; } HashTable (const SelfType& table): Mmged (table) @@ -140,11 +146,12 @@ public: this->pair_count = 0; this->load_factor = table.load_factor; this->threshold = table.bucket_size * table.load_factor / 100; + this->bucket_mpb_size = table.bucket_mpb_size; for (qse_size_t i = 0; i < table.bucket_size; i++) { Bucket* b = table.buckets[i]; - typename Bucket::Node* np; + BucketNode* np; for (np = b->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; @@ -171,7 +178,7 @@ public: for (qse_size_t i = 0; i < table.bucket_size; i++) { Bucket* b = table.buckets[i]; - typename Bucket::Node* np; + BucketNode* np; for (np = b->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; @@ -185,6 +192,20 @@ public: return *this; } + V& operator[] (const K& key) + { + Pair* pair = this->upsert (key); + QSE_ASSERT (pair != QSE_NULL); + return pair->value; + } + + const V& operator[] (const K& key) const + { + Pair* pair = this->upsert (key); + QSE_ASSERT (pair != QSE_NULL); + return pair->value; + } + qse_size_t getSize () const { return this->pair_count; @@ -218,111 +239,45 @@ public: return this->buckets[index]; } -#if 0 - V& operator[] (const K& key) +protected: + BucketNode* find_pair_node (const K& key, qse_size_t hc) const { - qse_size_t hc = this->hasher(key) % this->bucket_size; - - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; - if (this->comparator (key, e.key)) return e.value; + if (this->comparator(key, e.key)) return np; } - - if (this->pair_count >= threshold) - { - this->rehash (); - hc = this->hasher(key) % bucket_size; - } - - // insert a new key if the key is not found - Pair& e2 = this->buckets[hc]->append (Pair(key)); - this->pair_count++; - return e2.value; + return QSE_NULL; } - const V& operator[] (const K& key) const + Pair* find_pair (const K& key, qse_size_t hc) const { - qse_size_t hc = this->hasher(key) % this->bucket_size; - - Pair* pair = this->find_pair (key, hc); - if (pair) return pair->value; - - // insert a new key if the key is not found - Pair& new_pair = this->buckets[hc]->append (Pair(key)); - this->pair_count++; - return new_pair.value; + BucketNode* np = this->find_pair_node (key, hc); + if (np) return &np->value; + return QSE_NULL; } -#endif -protected: - template - Pair* find_pair_with_custom_key (const MK& key) const + template + BucketNode* find_pair_node_with_custom_key (const MK& key, qse_size_t hc) const { - MHASHER hash; MCOMPARATOR is_equal; - qse_size_t hc = hash(key) % this->bucket_size; - - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; - if (is_equal(key, e.key)) return &e; + if (is_equal(key, e.key)) return np; } return QSE_NULL; } -public: - /// \code - /// typedef QSE::HashTable IntTable; - /// struct IntClass - /// { - /// IntClass (int x = 0): x (x) {} - /// int x; - /// }; - /// struct IntClassHasher - /// { - /// qse_size_t operator() (const IntClass& v) const { return v.x; } - /// }; - /// struct IntClassComparator - /// { - /// bool operator() (const IntClass& v, int y) const { return v.x == y; } - /// } - /// }; - /// int main () - /// { - /// IntTable int_list (NULL, 1000); - /// ... - /// IntTable::Pair* pair = int_list.findPairWithCustomKey (IntClass(50)); - /// ... - /// } - /// \endcode - - template - const Pair* findPairWithCustomKey (const MK& key) const + template + Pair* find_pair_with_custom_key (const MK& key, qse_size_t hc) const { - return this->find_pair_with_custom_key (key); - } - - template - Pair* findPairWithCustomKey (const MK& key) - { - return this->find_pair_with_custom_key (key); - } - -protected: - Pair* find_pair (const K& key, qse_size_t hc) - { - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (this->comparator (key, e.key)) return &e; - } - + BucketNode* np = this->find_pair_node_with_custom_key (key, hc); + if (np) return &np->value; return QSE_NULL; } @@ -351,15 +306,15 @@ public: return QSE_NULL; } - V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) + V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node) { qse_size_t hc = this->hasher(key) % bucket_size; - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; - if (this->comparator (key, e.key)) + if (this->comparator(key, e.key)) { *hash_code = hc; *node = np; @@ -370,15 +325,15 @@ public: return QSE_NULL; } - const V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) const + const V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node) const { qse_size_t hc = this->hasher(key) % bucket_size; - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; - if (this->comparator (key, e.key)) + if (this->comparator(key, e.key)) { *hash_code = hc; *node = np; @@ -389,27 +344,68 @@ public: return QSE_NULL; } - int put (const K& key, const V& value) + /// \code + /// typedef QSE::HashTable IntTable; + /// struct IntClass + /// { + /// IntClass (int x = 0): x (x) {} + /// int x; + /// }; + /// struct IntClassHasher + /// { + /// qse_size_t operator() (const IntClass& v) const { return v.x; } + /// }; + /// struct IntClassComparator + /// { + /// bool operator() (const IntClass& v, int y) const { return v.x == y; } + /// } + /// }; + /// int main () + /// { + /// IntTable int_list (NULL, 1000); + /// ... + /// IntTable::Pair* pair = int_list.findPairWithCustomKey (IntClass(50)); + /// ... + /// } + /// \endcode + + template + Pair* findPairWithCustomKey (const MK& key) { - this->upsert (key, value); - return 0; + MHASHER hash; + return this->find_pair_with_custom_key (key, hash(key) % this->bucket_size); } - int putNew (const K& key, const V& value) + template + const Pair* findPairWithCustomKey (const MK& key) const { - return (this->insertNew(key,value) == QSE_NULL)? -1: 0; + MHASHER hash; + return this->find_pair_with_custom_key (key, hash(key) % this->bucket_size); } + /// The search() function returns the pointer to a pair of the \a key. + /// If no pair is found, it returns #QSE_NULL. + Pair* search (const K& key) + { + return this->find_pair (key, this->hasher(key) % this->bucket_size); + } + + /// The search() function returns the pointer to a pair of the \a key. + /// If no pair is found, it returns #QSE_NULL. + const Pair* search (const K& key) const + { + return this->find_pair (key, this->hasher(key) % this->bucket_size); + } + + /// The insert() function inserts a new pair with a \a key with the default value. + /// if the key is not found in the table. It returns the pointer to the + /// new pair inserted. If the key is found, it returns #QSE_NULL Pair* insert (const K& key) { qse_size_t hc = this->hasher(key) % bucket_size; - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (this->comparator (key, e.key)) return &e; - } + Pair* pair = this->find_pair (key, hc); + if (pair) return QSE_NULL; // existing pair found. if (this->pair_count >= threshold) { @@ -417,21 +413,21 @@ public: hc = this->hasher(key) % bucket_size; } - Pair& e = this->buckets[hc]->append (Pair(key)); + // insert a new pair + Pair& new_pair = this->buckets[hc]->append (Pair(key)); this->pair_count++; - return &e; + return &new_pair; } + /// The insert() function inserts a new pair with a \a key with a \a value. + /// if the key is not found in the table. It returns the pointer to the + /// new pair inserted. If the key is found, it returns #QSE_NULL Pair* insert (const K& key, const V& value) { qse_size_t hc = this->hasher(key) % bucket_size; - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (this->comparator (key, e.key)) return &e; - } + Pair* pair = this->find_pair (key, hc); + if (pair) return QSE_NULL; // existing pair found. if (this->pair_count >= threshold) { @@ -439,22 +435,32 @@ public: hc = this->hasher(key) % bucket_size; } - Pair& e = this->buckets[hc]->append (Pair(key,value)); + // insert a new pair + Pair& new_pair = this->buckets[hc]->append (Pair(key, value)); this->pair_count++; - return &e; + return &new_pair; } -#if 0 - Pair* upsert (const K& Key) + /// The update() function updates an existing pair of the \a key + /// with a \a value and returns a pointer to the pair. If the key + /// is not found, it returns #QSE_NULL. + Pair* update (const K& key, const V& value) + { + qse_size_t hc = this->hasher(key) % bucket_size; + Pair* pair = this->find_pair (key, hc); + if (pair) pair->value = value; // update the existing pair + return pair; + } + + /// The upsert() function inserts a new pair with a \a key and a \a value + /// if the key is not found in the table. If it is found, it updated the + /// existing pair with a given \a value. + Pair* upsert (const K& key) { qse_size_t hc = this->hasher(key) % this->bucket_size; Pair* pair = this->find_pair (key, hc); - if (pair) - { - // don't change the existing value. - return pair - } + if (pair) return pair; // return the existing pair if (this->pair_count >= threshold) { @@ -462,13 +468,15 @@ public: hc = this->hasher(key) % this->bucket_size; } - // insert a new key if the key is not found + // insert a new pair if the key is not found Pair& new_pair = this->buckets[hc]->append (Pair(key)); this->pair_count++; - return &new_pair + return &new_pair; } -#endif + /// The upsert() function inserts a new pair with a \a key and a \a value + /// if the key is not found in the table. If it is found, it updated the + /// existing pair with a given \a value. Pair* upsert (const K& key, const V& value) { qse_size_t hc = this->hasher(key) % this->bucket_size; @@ -476,6 +484,7 @@ public: Pair* pair = this->find_pair (key, hc); if (pair) { + // update the value of the existing pair pair->value = value; return pair; } @@ -486,126 +495,14 @@ public: hc = this->hasher(key) % this->bucket_size; } - // insert a new key if the key is not found - Pair& new_pair = this->buckets[hc]->append (Pair(key,value)); + // insert a new pair if the key is not found + Pair& new_pair = this->buckets[hc]->append (Pair(key, value)); this->pair_count++; return &new_pair; - - /* - qse_size_t hc = this->hasher(key) % this->bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (key == e.key) - { - e.value = value; - return &e.value; - } - } - - if (this->pair_count >= threshold) - { - this->rehash (); - hc = this->hasher(key) % bucket_size; - } - - Pair& e = this->buckets[hc]->append (Pair(key,value)); - this->pair_count++; - return &e.value; - */ } - -#if 0 - V* insertNew (const K& key) - { - qse_size_t hc = this->hasher(key) % bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (key == e.key) return QSE_NULL; - } - - if (this->pair_count >= threshold) - { - this->rehash (); - hc = this->hasher(key) % bucket_size; - } - - Pair& e = this->buckets[hc]->append (Pair(key)); - this->pair_count++; - return &e.value; - } - - V* insertNew (const K& key, const V& value) - { - qse_size_t hc = this->hasher(key) % bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (key == e.key) return QSE_NULL; - } - - if (this->pair_count >= threshold) - { - this->rehash (); - hc = this->hasher(key) % bucket_size; - } - - Pair& e = this->buckets[hc]->append (Pair(key, value)); - this->pair_count++; - return &e.value; - } -#endif - - - template - int removeWithCustomKey (const MK& key) - { - MHASHER h; - qse_size_t hc = h(key) % bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (key == e.key) - { - this->buckets[hc]->remove (np); - this->pair_count--; - return 0; - } - } - - return -1; - } - - int remove (const K& key) - { - qse_size_t hc = this->hasher(key) % bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (key == e.key) - { - this->buckets[hc]->remove (np); - this->pair_count--; - return 0; - } - } - - return -1; - } - - int remove (qse_size_t hc, typename Bucket::Node* np) +protected: + int remove (qse_size_t hc, BucketNode* np) { // // WARNING: this method should be used with extra care. @@ -615,59 +512,35 @@ public: return 0; } -#if 0 - qse_size_t removeValue (const V& value) - { - qse_size_t count = 0; - - for (qse_size_t i = 0; i < this->bucket_size; i++) - { - typename Bucket::Node* np, * np2; - np = this->buckets[i]->getHeadNode(); - while (np != QSE_NULL) - { - Pair& e = np->value; - np2 = np->getNext (); - if (value == e.value) - { - this->remove (i, np); - count++; - } - np = np2; - } - } - - return count; - } -#endif - - bool containsKey (const K& key) const +public: + int remove (const K& key) { qse_size_t hc = this->hasher(key) % bucket_size; - - typename Bucket::Node* np; - for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) + + BucketNode* np = this->find_pair_node (key, hc); + if (np) { - Pair& e = np->value; - if (key == e.key) return true; + this->remove (hc, np); + return 0; } - return false; + return -1; } - bool containsValue (const K& value) const + template + int removeWithCustomKey (const MK& key) { - for (qse_size_t i = 0; i < bucket_size; i++) + MHASHER hash; + qse_size_t hc = hash(key) % this->bucket_size; + + BucketNode* np = this->find_pair_node_with_custom_key (key, hc); + if (np) { - typename Bucket::Node* np; - for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) - { - Pair& e = np->value; - if (value == e.value) return true; - } + this->remove (hc, np); + return 0; } - return false; + return -1; } void clear (qse_size_t new_bucket_size = 0) @@ -693,7 +566,7 @@ public: { for (qse_size_t i = 0; i < this->bucket_size; i++) { - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { const Pair& e = np->value; @@ -711,7 +584,7 @@ public: { for (qse_size_t i = 0; i < this->bucket_size; i++) { - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { Pair& e = np->value; @@ -721,16 +594,17 @@ public: return 0; } - + protected: mutable qse_size_t pair_count; mutable qse_size_t bucket_size; mutable Bucket** buckets; mutable qse_size_t threshold; - qse_size_t load_factor; - HASHER hasher; - COMPARATOR comparator; - RESIZER resizer; + qse_size_t load_factor; + qse_size_t bucket_mpb_size; + HASHER hasher; + COMPARATOR comparator; + RESIZER resizer; void rehash () const { @@ -742,7 +616,7 @@ protected: for (qse_size_t i = 0; i < this->bucket_size; i++) { /* - typename Bucket::Node* np; + BucketNode* np; for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { const Pair& e = np->value; @@ -756,10 +630,10 @@ protected: // if the bucket uses a memory pool, this would not // work. fortunately, the hash table doesn't use it // for a bucket. - typename Bucket::Node* np = this->buckets[i]->getHeadNode(); + BucketNode* np = this->buckets[i]->getHeadNode(); while (np) { - typename Bucket::Node* next = np->getNext(); + BucketNode* next = np->getNext(); const Pair& e = np->value; qse_size_t hc = this->hasher(e.key) % new_bucket_size; new_buckets[hc]->appendNode (this->buckets[i]->yield(np)); diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp index ba694b1f..5f9381b6 100644 --- a/qse/include/qse/cmn/LinkedList.hpp +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -34,14 +34,14 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// -template class LinkedList; +template class LinkedList; -template +template class LinkedListNode { public: - friend class LinkedList; - typedef LinkedListNode SelfType; + friend class LinkedList; + typedef LinkedListNode SelfType; T value; // you can use this variable or accessor functions below @@ -79,14 +79,120 @@ protected: } }; +template +class LinkedListIterator { +public: + friend class LinkedList; + typedef LinkedListNode Node; + typedef LinkedListIterator SelfType; + + LinkedListIterator (): current(QSE_NULL) {} + LinkedListIterator (Node* node): current(node) {} + LinkedListIterator (const SelfType& it): current (it.current) {} + + SelfType& operator= (const SelfType& it) + { + this->current = it.current; + return *this; + } + + SelfType& operator++ () // prefix increment + { + QSE_ASSERT (this->current != QSE_NULL); + this->current = this->current->getNext(); + return *this; + } + + SelfType operator++ (int) // postfix increment + { + QSE_ASSERT (this->current != QSE_NULL); + SelfType saved (*this); + this->current = this->current->getNext(); //++(*this); + return saved; + } + + SelfType& operator-- () // prefix decrement + { + QSE_ASSERT (this->current != QSE_NULL); + this->current = this->current->getPrev(); + return *this; + } + + SelfType operator-- (int) // postfix decrement + { + QSE_ASSERT (this->current != QSE_NULL); + SelfType saved (*this); + this->current = this->current->getPrev(); //--(*this); + return saved; + } + + int operator== (const SelfType& it) const + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current == it.current; + } + + int operator!= (const SelfType& it) const + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current != it.current; + } + + bool isValid () const + { + return this->current != QSE_NULL; + } + + T& getValue () + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current->getValue(); + } + + const T& getValue () const + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current->getValue(); + } + + SelfType& setValue (const T& v) + { + QSE_ASSERT (this->current != QSE_NULL); + this->current->setValue (v); + return *this; + } + + Node* getNode () + { + return this->current; + } + +protected: + Node* current; +}; + +template +struct LinkedListComparator +{ + // it must return true if two values are equal + bool operator() (const T& v1, const T& v2) const + { + return v1 == v2; + } +}; + /// /// The LinkedList class provides a template for a doubly-linked list. /// -template class LinkedList: public Mmged +template > class LinkedList: public Mmged { public: - typedef LinkedList SelfType; - typedef LinkedListNode Node; + typedef LinkedList SelfType; + typedef LinkedListNode Node; + typedef LinkedListIterator Iterator; + + typedef Mpool DefaultMpool; + typedef LinkedListComparator DefaultComparator; enum { @@ -168,7 +274,35 @@ public: // insert an externally created node. // may need to take extra care when using this method. - Node* insertNode (Node* pos, Node* node); + Node* insertNode (Node* pos, Node* node) + { + if (pos == QSE_NULL) + { + if (this->node_count == 0) + { + QSE_ASSERT (head_node == QSE_NULL); + QSE_ASSERT (tail_node == QSE_NULL); + this->head_node = this->tail_node = node; + } + else + { + node->prev = this->tail_node; + this->tail_node->next = node; + this->tail_node = node; + } + } + else + { + node->next = pos; + node->prev = pos->prev; + if (pos->prev) pos->prev->next = node; + else this->head_node = node; + pos->prev = node; + } + + this->node_count++; + return node; + } // create a new node to hold the value and insert it. Node* insertValue (Node* pos, const T& value) @@ -432,7 +566,7 @@ public: { for (Node* p = this->head_node; p; p = p->next) { - if (value == p->value) return p; + if (this->comparator (value, p->value)) return p; } return QSE_NULL; } @@ -441,7 +575,7 @@ public: { for (Node* p = tail_node; p; p = p->prev) { - if (value == p->value) return p; + if (this->comparator (value, p->value)) return p; } return QSE_NULL; } @@ -450,7 +584,7 @@ public: { for (Node* p = head; p; p = p->next) { - if (value == p->value) return p; + if (this->comparator (value, p->value)) return p; } return QSE_NULL; } @@ -459,17 +593,17 @@ public: { for (Node* p = tail; p; p = p->prev) { - if (value == p->value) return p; + if (this->comparator (value, p->value)) return p; } return QSE_NULL; - } + } qse_size_t findFirstIndex (const T& value) const { qse_size_t index = 0; for (Node* p = this->head_node; p; p = p->next) { - if (value == p->value) return index; + if (this->comparator (value, p->value)) return index; index++; } return INVALID_INDEX; @@ -481,7 +615,7 @@ public: for (Node* p = tail_node; p; p = p->prev) { index--; - if (value == p->value) return index; + if (this->comparator (value, p->value)) return index; } return INVALID_INDEX; } @@ -513,6 +647,11 @@ public: this->mp.dispose (); } + //void reverse () + //{ + // + //} + typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); void traverse (TraverseCallback callback, Node* start) @@ -533,44 +672,19 @@ public: } } + Iterator getIterator (qse_size_t index = 0) const + { + return Iterator (this->getNodeAt(index)); + } + protected: MPOOL mp; + COMPARATOR comparator; Node* head_node; Node* tail_node; qse_size_t node_count; }; -template -inline typename LinkedList::Node* LinkedList::insertNode (Node* pos, Node* node) -{ - if (pos == QSE_NULL) - { - if (this->node_count == 0) - { - QSE_ASSERT (head_node == QSE_NULL); - QSE_ASSERT (tail_node == QSE_NULL); - this->head_node = this->tail_node = node; - } - else - { - node->prev = this->tail_node; - this->tail_node->next = node; - this->tail_node = node; - } - } - else - { - node->next = pos; - node->prev = pos->prev; - if (pos->prev) pos->prev->next = node; - else this->head_node = node; - pos->prev = node; - } - - this->node_count++; - return node; -} - ///////////////////////////////// QSE_END_NAMESPACE(QSE) /////////////////////////////////