source: XMLIO_V2/external/src/POCO/Foundation.save/Poco/LinearHashTable.h @ 80

Last change on this file since 80 was 80, checked in by ymipsl, 14 years ago

ajout lib externe

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1//
2// LinearHashTable.h
3//
4// $Id: //poco/1.3/Foundation/include/Poco/LinearHashTable.h#5 $
5//
6// Library: Foundation
7// Package: Hashing
8// Module:  LinearHashTable
9//
10// Definition of the LinearHashTable class.
11//
12// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
13// and Contributors.
14//
15// Permission is hereby granted, free of charge, to any person or organization
16// obtaining a copy of the software and accompanying documentation covered by
17// this license (the "Software") to use, reproduce, display, distribute,
18// execute, and transmit the Software, and to prepare derivative works of the
19// Software, and to permit third-parties to whom the Software is furnished to
20// do so, all subject to the following:
21//
22// The copyright notices in the Software and this entire statement, including
23// the above license grant, this restriction and the following disclaimer,
24// must be included in all copies of the Software, in whole or in part, and
25// all derivative works of the Software, unless such copies or derivative
26// works are solely in the form of machine-executable object code generated by
27// a source language processor.
28//
29// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
32// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
33// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
34// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35// DEALINGS IN THE SOFTWARE.
36//
37
38
39#ifndef Foundation_LinearHashTable_INCLUDED
40#define Foundation_LinearHashTable_INCLUDED
41
42
43#include "Poco/Foundation.h"
44#include "Poco/Hash.h"
45#include <functional>
46#include <algorithm>
47#include <vector>
48#include <utility>
49#include <cstddef>
50
51
52namespace Poco {
53
54
55template <class Value, class HashFunc = Hash<Value> >
56class LinearHashTable
57        /// This class implements a linear hash table.
58        ///
59        /// In a linear hash table, the available address space
60        /// grows or shrinks dynamically. A linar hash table thus
61        /// supports any number of insertions or deletions without
62        /// lookup or insertion performance deterioration.
63        ///
64        /// Linear hashing was discovered by Witold Litwin in 1980
65        /// and described in the paper LINEAR HASHING: A NEW TOOL FOR FILE AND TABLE ADDRESSING.
66        ///
67        /// For more information on linear hashing, see <http://en.wikipedia.org/wiki/Linear_hash>.
68        ///
69        /// The LinearHashTable is not thread safe.
70        ///
71        /// Value must support comparison for equality.
72        ///
73        /// Find, insert and delete operations are basically O(1) with regard
74        /// to the total number of elements in the table, and O(N) with regard
75        /// to the number of elements in the bucket where the element is stored.
76        /// On average, every bucket stores one element; the exact number depends
77        /// on the quality of the hash function. In most cases, the maximum number of
78        /// elements in a bucket should not exceed 3.
79{
80public:
81        typedef Value               ValueType;
82        typedef Value&              Reference;
83        typedef const Value&        ConstReference;
84        typedef Value*              Pointer;
85        typedef const Value*        ConstPointer;
86        typedef HashFunc            Hash;
87        typedef std::vector<Value>  Bucket;
88        typedef std::vector<Bucket> BucketVec;
89        typedef typename Bucket::iterator    BucketIterator;
90        typedef typename BucketVec::iterator BucketVecIterator;
91
92        class ConstIterator: public std::iterator<std::forward_iterator_tag, Value>
93        {
94        public:
95                ConstIterator()
96                {
97                }
98               
99                ConstIterator(const BucketVecIterator& vecIt, const BucketVecIterator& endIt, const BucketIterator& buckIt):
100                        _vecIt(vecIt),
101                        _endIt(endIt),
102                        _buckIt(buckIt)
103                {
104                }
105
106                ConstIterator(const ConstIterator& it):
107                        _vecIt(it._vecIt),
108                        _endIt(it._endIt),
109                        _buckIt(it._buckIt)
110                {
111                }
112               
113                ConstIterator& operator = (const ConstIterator& it)
114                {
115                        ConstIterator tmp(it);
116                        swap(tmp);
117                        return *this;
118                }
119               
120                void swap(ConstIterator& it)
121                {
122                        using std::swap;
123                        swap(_vecIt, it._vecIt);
124                        swap(_endIt, it._endIt);
125                        swap(_buckIt, it._buckIt);
126                }
127               
128                bool operator == (const ConstIterator& it) const
129                {
130                        return _vecIt == it._vecIt && (_vecIt == _endIt || _buckIt == it._buckIt);
131                }
132
133                bool operator != (const ConstIterator& it) const
134                {
135                        return _vecIt != it._vecIt || (_vecIt != _endIt && _buckIt != it._buckIt);
136                }
137               
138                const typename Bucket::value_type& operator * () const
139                {
140                        return *_buckIt;
141                }
142
143                const typename Bucket::value_type* operator -> () const
144                {
145                        return &*_buckIt;
146                }
147               
148                ConstIterator& operator ++ () // prefix
149                {
150                        if (_vecIt != _endIt)
151                        {
152                                ++_buckIt;
153                                while (_vecIt != _endIt && _buckIt == _vecIt->end())
154                                {
155                                        ++_vecIt;
156                                        if (_vecIt != _endIt) _buckIt = _vecIt->begin();
157                                }
158                        }
159                        return *this;
160                }
161               
162                ConstIterator operator ++ (int) // postfix
163                {
164                        ConstIterator tmp(*this);
165                        ++*this;
166                        return tmp;
167                }
168               
169        protected:
170                BucketVecIterator _vecIt;
171                BucketVecIterator _endIt;
172                BucketIterator    _buckIt;
173               
174                friend class LinearHashTable;
175        };
176       
177        class Iterator: public ConstIterator
178        {
179        public:
180                Iterator()
181                {
182                }
183               
184                Iterator(const BucketVecIterator& vecIt, const BucketVecIterator& endIt, const BucketIterator& buckIt):
185                        ConstIterator(vecIt, endIt, buckIt)
186                {
187                }
188
189                Iterator(const Iterator& it):
190                        ConstIterator(it)
191                {
192                }
193               
194                Iterator& operator = (const Iterator& it)
195                {
196                        Iterator tmp(it);
197                        swap(tmp);
198                        return *this;
199                }
200               
201                void swap(Iterator& it)
202                {
203                        ConstIterator::swap(it);
204                }
205                               
206                typename Bucket::value_type& operator * ()
207                {
208                        return *this->_buckIt;
209                }
210
211                const typename Bucket::value_type& operator * () const
212                {
213                        return *this->_buckIt;
214                }
215
216                typename Bucket::value_type* operator -> ()
217                {
218                        return &*this->_buckIt;
219                }
220
221                const typename Bucket::value_type* operator -> () const
222                {
223                        return &*this->_buckIt;
224                }
225               
226                Iterator& operator ++ () // prefix
227                {
228                        ConstIterator::operator ++ ();
229                        return *this;
230                }
231               
232                Iterator operator ++ (int) // postfix
233                {
234                        Iterator tmp(*this);
235                        ++*this;
236                        return tmp;
237                }
238
239                friend class LinearHashTable;
240        };
241       
242        LinearHashTable(std::size_t initialReserve = 64): 
243                _split(0),
244                _front(1),
245                _size(0)
246                /// Creates the LinearHashTable, using the given initialReserve.
247        {
248                _buckets.reserve(calcSize(initialReserve));
249                _buckets.push_back(Bucket());
250        }
251       
252        LinearHashTable(const LinearHashTable& table):
253                _buckets(table._buckets),
254                _split(table._split),
255                _front(table._front),
256                _size(table._size)
257                /// Creates the LinearHashTable by copying another one.
258        {
259        }
260       
261        ~LinearHashTable()
262                /// Destroys the LinearHashTable.
263        {
264        }
265       
266        LinearHashTable& operator = (const LinearHashTable& table)
267                /// Assigns another LinearHashTable.
268        {
269                LinearHashTable tmp(table);
270                swap(tmp);
271                return *this;
272        }
273       
274        void swap(LinearHashTable& table)
275                /// Swaps the LinearHashTable with another one.
276        {
277                using std::swap;
278                swap(_buckets, table._buckets);
279                swap(_split, table._split);
280                swap(_front, table._front);
281                swap(_size, table._size);
282        }
283       
284        ConstIterator begin() const
285                /// Returns an iterator pointing to the first entry, if one exists.
286        {
287                BucketVecIterator it(_buckets.begin());
288                BucketVecIterator end(_buckets.end());
289                while (it != end && it->empty())
290                {
291                        ++it;
292                }
293                if (it == end)
294                        return this->end();
295                else
296                        return ConstIterator(it, end, it->begin());
297        }
298       
299        ConstIterator end() const
300                /// Returns an iterator pointing to the end of the table.
301        {
302                return ConstIterator(_buckets.end(), _buckets.end(), _buckets.front().end());
303        }
304       
305        Iterator begin()
306                /// Returns an iterator pointing to the first entry, if one exists.
307        {
308                BucketVecIterator it(_buckets.begin());
309                BucketVecIterator end(_buckets.end());
310                while (it != end && it->empty())
311                {
312                        ++it;
313                }
314                if (it == end)
315                        return this->end();
316                else
317                        return Iterator(it, end, it->begin());
318        }
319       
320        Iterator end()
321                /// Returns an iterator pointing to the end of the table.
322        {
323                return Iterator(_buckets.end(), _buckets.end(), _buckets.front().end());
324        }
325               
326        ConstIterator find(const Value& value) const
327                /// Finds an entry in the table.
328        {
329                std::size_t addr = bucketAddress(value);
330                BucketVecIterator it(_buckets.begin() + addr);
331                BucketIterator buckIt(std::find(it->begin(), it->end(), value));
332                if (buckIt != it->end())
333                        return ConstIterator(it, _buckets.end(), buckIt);
334                else
335                        return end();
336        }
337
338        Iterator find(const Value& value)
339                /// Finds an entry in the table.
340        {
341                std::size_t addr = bucketAddress(value);
342                BucketVecIterator it(_buckets.begin() + addr);
343                BucketIterator buckIt(std::find(it->begin(), it->end(), value));
344                if (buckIt != it->end())
345                        return Iterator(it, _buckets.end(), buckIt);
346                else
347                        return end();
348        }
349       
350        std::size_t count(const Value& value) const
351                /// Returns the number of elements with the given
352                /// value, with is either 1 or 0.
353        {
354                return find(value) != end() ? 1 : 0;
355        }
356       
357        std::pair<Iterator, bool> insert(const Value& value)
358                /// Inserts an element into the table.
359                ///
360                /// If the element already exists in the table,
361                /// a pair(iterator, false) with iterator pointing to the
362                /// existing element is returned.
363                /// Otherwise, the element is inserted an a
364                /// pair(iterator, true) with iterator
365                /// pointing to the new element is returned.
366        {
367                split();
368                std::size_t addr = bucketAddress(value);
369                BucketVecIterator it(_buckets.begin() + addr);
370                BucketIterator buckIt(std::find(it->begin(), it->end(), value));
371                if (buckIt == it->end())
372                {
373                        buckIt = it->insert(buckIt, value);
374                        ++_size;
375                        return std::make_pair(Iterator(it, _buckets.end(), buckIt), true);
376                }
377                else
378                {
379                        return std::make_pair(Iterator(it, _buckets.end(), buckIt), false);
380                }
381        }
382       
383        void erase(Iterator it)
384                /// Erases the element pointed to by it.
385        {
386                if (it != end())
387                {
388                        it._vecIt->erase(it._buckIt);
389                        --_size;
390                        merge();
391                }
392        }
393       
394        void erase(const Value& value)
395                /// Erases the element with the given value, if it exists.
396        {
397                Iterator it = find(value);
398                erase(it);
399        }
400       
401        void clear()
402                /// Erases all elements.
403        {
404                LinearHashTable empty;
405                swap(empty);
406        }
407       
408        std::size_t size() const
409                /// Returns the number of elements in the table.
410        {
411                return _size;
412        }
413       
414        bool empty() const
415                /// Returns true iff the table is empty.
416        {
417                return _size == 0;
418        }
419       
420protected:
421        std::size_t bucketAddress(const Value& value) const
422        {
423                std::size_t n = _hash(value);
424                if (n % _front >= _split)
425                        return n % _front;
426                else
427                        return n % (2*_front);
428        }
429       
430        void split()
431        {
432                if (_split == _front)
433                {
434                        _split = 0;
435                        _front *= 2;
436                        _buckets.reserve(_front*2);
437                }
438                Bucket tmp;
439                _buckets.push_back(tmp);
440                _buckets[_split].swap(tmp);
441                ++_split;
442                for (BucketIterator it = tmp.begin(); it != tmp.end(); ++it)
443                {
444                        using std::swap;
445                        std::size_t addr = bucketAddress(*it);
446                        _buckets[addr].push_back(Value());
447                        swap(*it, _buckets[addr].back());
448                }
449        }
450       
451        void merge()
452        {
453                if (_split == 0)
454                {
455                        _front /= 2;
456                        _split = _front;
457                }
458                --_split;
459                Bucket tmp;
460                tmp.swap(_buckets.back());
461                _buckets.pop_back();
462                for (BucketIterator it = tmp.begin(); it != tmp.end(); ++it)
463                {
464                        using std::swap;
465                        std::size_t addr = bucketAddress(*it);
466                        _buckets[addr].push_back(Value());
467                        swap(*it, _buckets[addr].back());
468                }
469        }
470       
471        static std::size_t calcSize(std::size_t initialSize)
472        {
473                std::size_t size = 32;
474                while (size < initialSize) size *= 2;
475                return size;
476        }
477       
478private:
479        // Evil hack: _buckets must be mutable because both ConstIterator and Iterator hold
480        // ordinary iterator's (not const_iterator's).
481        mutable BucketVec _buckets;
482        std::size_t _split;
483        std::size_t _front;
484        std::size_t _size;
485        HashFunc    _hash;
486};
487
488
489} // namespace Poco
490
491
492#endif // Foundation_LinearHashTable_INCLUDED
Note: See TracBrowser for help on using the repository browser.