root/trunk/containers/include/hash_table.h @ 3142

Revision 3142, 52.6 KB (checked in by plasmahh, 8 months ago)
  • happy new year!
  • Property svn:eol-style set to native
Line 
1
2
3
4#include <iostream>
5#include <cassert>
6#include <vector>
7#include <algorithm>
8#include <stdexcept>
9#include <cstring>
10
11#include "boost/mpl/if.hpp"
12#include "boost/utility/enable_if.hpp"
13
14namespace iwear
15{
16
17template<class T, size_t N>
18/*constexpr*/ size_t array_size( T(& )[N] )
19{
20        return N;
21}
22
23#define asize(x) (sizeof(x) / sizeof(x[0]))
24/*
25 * This class aims to be a quite versatile hashtable, where you can control
26 * various parameters of its behaviour via template parameters.
27 */
28
29/**
30 * These enums control basic behaviours of the hashing functions built in. If
31 * you need something else for the trivial types, you need to roll your own
32 * structure that does this.
33 * @note You can create specializations for various other hashing classes
34 * yourself, and specify them at the same point where you instantiate them
35 * otherwise. To do that, simply specialize for other numerical values, like
36 * hash<T,(hashclass)3> and use that type wherever you want.
37 */
38enum class hashclass : int
39{
40        identity, ///< If possible, use the value as the result of the hash, to suppress possible errors we static_cast to size_type
41        trivial,  ///< Use a trivial hashing, like multiplication with a large prime
42        fnv       ///< Use a hashing scheme similar to fnv (but not quite exactly)
43};
44
45/**
46 * This is a value metafunction that takes an integer as input and outputs the
47 * same value of the type hashclass. Whenever the input could be something
48 * convertible to int, this is a wrapper for the case you don't like casts. You
49 * can use it like make_hashclass<5>::value instead of (hash_class)5
50 */
51template<int hc>
52struct make_hashclass
53{
54    static const hashclass value = (hashclass)hc;
55};
56
57/**
58 * This class is for the actual hashing. The user is supposed to specialize it
59 * for his own types in order to get the hashing behaviour he wants. It might
60 * be possible though, that for some reasons another hashing is needed for the
61 * same datatype. To compensate for this we allow for specifying the type of
62 * the hash struct later in the hash_table so that a user can use its own
63 * there.
64 * @note per default a trivial hashing is used, which is often a good balance
65 * between speed and degradation effects.
66 * @note We will always use this type without explicitly specifying its
67 * namespace. Therefore it could be possible that sometimes something from your
68 * namespace is picked up, be aware of that.
69 * @warning Various hashes have different degradation properties, like
70 * avalanche effects and similar. Consider carefully what you chose here, and
71 * in that consideration, think about who controls the data. If you control the
72 * data you can usually be much more lax with the requirements as you can make
73 * sure that no strange clustering effects can occur.
74 */
75template<class T, hashclass HC >
76struct hash
77{
78    typedef size_t size_type;
79    typedef T item_type;
80private:
81    /**
82     * If you get a compile error here saying that this is private, you need to
83     * specialize your own version of hash for your item_type with this
84     * function not being private. This generic version is just to communicate
85     * a defined interface.
86     */
87    size_type operator()( const item_type& i );
88    size_type operator()( item_type* i );
89};
90
91namespace __detail
92{
93
94template<class size_type, int N>
95struct roundup
96{
97        static size_type roundup_recurse( size_type v )
98        {
99                v = roundup<size_type,N/2>::roundup_recurse(v);
100                v |= v >> N;
101                return v;
102    }
103};
104
105template<class size_type>
106struct roundup<size_type,1>
107{
108        static size_type roundup_recurse( size_type v )
109        {
110                v |= v >> 1;
111                return v;
112        }
113};
114
115template<class size_type>
116size_type roundup2( size_type v )
117{
118        v--;
119        v = roundup<size_type,sizeof(v)>::roundup_recurse(v);
120        v++;
121        return v;
122}
123
124} // namespace __detail
125
126#if 0  // old shit ;)
127/**
128 * This class controls how the sizes of the hashtable are selected, as well as
129 * how the hash value is actually transformed into an index.
130 * @param binary decides whether the hashtable uses power of two sizes only,
131 * and then the operator& to determine indices or whether a predefined list of
132 * primes is used with the operator%.
133 */
134template<bool binary >
135struct hash_selection
136{
137    typedef size_t size_type;
138
139    /**
140     * With this we control whether the hashtable will automatically resize
141     * when it detects after an insert that it is now too small, or whether the
142     * user is responsible for calling the corresponding check function.
143     * @note that in no case a check for the size is done, when the slot in the
144     * hashtable that was found wasn't already occupied.
145     */
146    static const bool auto_resize;
147    /**
148     * required helper function that will determine the type of the pointer
149     * being used. You can write your own variant, that will use e.g.
150     * boost::offset_ptr so all pointers that are permanently stored in memory
151     * are of such a type which means you can store things in shared memory or
152     * in a memory mapped file you will be able to relocate.
153     */
154    template<class T>
155    struct add_pointer
156    {
157        typedef T* type;
158    };
159
160    /**
161     * The default metafunction for creating the slot item type assumes that we
162     * are using a singly linked list for our hashtable.
163     */
164    template<class T>
165    struct slot_item
166    {
167        typedef typename add_pointer<T>::type type;
168    };
169
170    /**
171     * Transforms the hash into an actual index.
172     * @param hash is the hash as gathered from the hash structure
173     * @param size is the current size of the hashtable in number of slots
174     */
175
176    static size_type index( size_type hash, size_type size );
177
178    /**
179     * @returns true if a resize of the hashtable is recommended, making the
180     * hashtable actually bigger. If a shrink is possible, this does not mean a
181     * resize is recommended, so this function returns false.
182     */
183    static bool need_resize( size_type size, size_type filled );
184
185    /**
186      Do a resize so the size vs filled ratio is optimized in case too much
187     * slots are filled. If there are already enough free slots, no change is
188     * made.
189     * @returns true iff an actual resize was made.
190     */
191    static bool resize( size_type size, size_type filled );
192
193    /**
194     * Shrinks a hashtable to the least minimum necessary for a proper
195     * fillratio of the table. This might be significantly slower as the
196     * recommended size used in resize() so that you should only ever call this
197     * if you think the hashtable will not be filled in the future.
198     */
199    static bool shrink( size_type size, size_type filled );
200};
201
202template<>
203struct hash_selection<false>
204{
205    template<class R>
206    struct add_pointer
207    {
208        typedef R* type;
209    };
210
211    template<class R>
212    struct slot_item
213    {
214        typedef typename add_pointer<R>::type type;
215    };
216
217    typedef size_t size_type;
218    static size_type index( size_type hash, size_type size )
219    {
220#ifdef DEBUG
221        std::cerr << "hash = " << hash << ", size = " << size << "\n";
222#endif
223        return hash % size;
224    }
225};
226#endif
227
228struct slot_selector_modulo
229{
230        static size_t mask_from_length( size_t len )
231        {
232                return len;
233        }
234
235        size_t operator()( size_t hsum, size_t mask ) const
236        { 
237#ifdef DEBUG
238                std::cerr << "slot_selector_modulo()(" << hsum << " % " << mask << " == " << (hsum % mask) << "\n";
239#endif
240                return hsum % mask;
241        }
242};
243
244struct slot_selector_power2
245{
246        static size_t mask_from_length( size_t len )
247        {
248                return len - 1;
249        }
250
251        size_t operator()( size_t hsum, size_t mask ) const 
252        {
253#ifdef DEBUG
254                std::cerr << "slot_selector_power2()(" << hsum << " & " << mask << " == " << (hsum & mask) << "\n";
255#endif
256                // assert( mask+1 is power of 2 );
257                return hsum & mask;
258        }
259};
260
261
262// ############################################# # # # # # # # # # # # # # # # # # # # # # # # #
263//
264// for the factor 1.1
265size_t primetable11[] =
266{
267        2,                              3,                              5,                              7,                              11,                             13,                             
268        17,                             19,                             23,                             29,                             31,                             37,                             
269        41,                             43,                             53,                             59,                             67,                             73,                             
270        83,                             89,                             97,                             107,                    127,                    139,                   
271        157,                    167,                    191,                    211,                    223,                    251,                   
272        269,                    293,                    331,                    359,                    389,                    431,                   
273        479,                    521,                    569,                    631,                    691,                    757,                   
274        827,                    911,                    1009,                   1103,                   1213,                   1327,                   
275        1459,                   1607,                   1777,                   1949,                   2137,                   2347,                   
276        2591,                   2843,                   3137,                   3449,                   3779,                   4157,                   
277        4583,                   5039,                   5527,                   6079,                   6689,                   7369,                   
278        8089,                   8923,                   9787,                   10771,                  11863,                  13033,                 
279        14327,                  15761,                  17333,                  19069,                  20981,                  23071,                 
280        25391,                  27917,                  30703,                  33773,                  37159,                  40867,                 
281        44953,                  49451,                  54401,                  59833,                  65827,                  72421,                 
282        79631,                  87613,                  96353,                  105997,                 116593,                 128257,                 
283        141073,                 155191,                 170701,                 187763,                 206543,                 227189,                 
284        249911,                 274909,                 302399,                 332641,                 365903,                 402487,                 
285        442721,                 487007,                 535697,                 589273,                 648191,                 713021,                 
286        784307,                 862739,                 949019,                 1043921,                1148311,                1263133,               
287        1389439,                1528399,                1681241,                1849349,                2034283,                2237743,               
288        2461477,                2707651,                2978399,                3276241,                3603857,                3964229,               
289        4360649,                4796749,                5276387,                5804023,                6384439,                7022867,               
290        7725161,                8497681,                9347441,                10282177,               11310413,               12441439,               
291        13685579,               15054157,               16559561,               18215501,               20037053,               22040771,               
292        24244837,               26669317,               29336243,               32269877,               35496869,               39046541,               
293        42951203,               47246359,               51970957,               57168043,               62884859,               69173333,               
294        76090681,               83699761,               92069729,               101276699,              111404369,              122544787,             
295        134799271,              148279217,              163107157,              179417839,              197359663,              217095589,             
296        238805207,              262685693,              288954269,              317849681,              349634651,              384598153,             
297        423057949,              465363781,              511900133,              563090189,              619399213,              681339121,             
298        749473051,              824420407,              906862427,              997548689,              1097303609,             1207033967,             
299        1327737391,             1460511163,             1606562357,             1767218597,             1943940541,             2138334589,             
300        2352168083UL,   2587384981UL,   2846123519UL,   3130735931UL,   3443809657UL,   3788190661UL,           
301        4167009773UL,           
302};
303
304// for the factor 1.5
305size_t primetable15[] = 
306{
307        2,                              5,                              7,                              11,                             17,                             29,                             
308        41,                             59,                             89,                             137,                    199,                    307,                   
309        449,                    673,                    1009,                   1511,                   2267,                   3391,                   
310        5087,                   7639,                   11443,                  17167,                  25741,                  38611,                 
311        57917,                  86923,                  130337,                 195469,                 293201,                 439799,                 
312        659689,                 989533,                 1484291,                2226431,                3339643,                5009471,               
313        7514231,                11271319,               16906949,               25360441,               38040619,               57060931,               
314        85591417,               128387137,              192580621,              288870937,              433306427,              649959679,             
315        974939417,              1462409083,             2193613607UL,   3290420401UL
316};
317
318template<
319int grow_load_pm,
320int perfect_load_pm,
321int shrink_load_pm
322>
323struct resize_base
324{
325// XXX one day take some time and think about whether we can safely do all this
326// with integer only maths. Or even provide a template parameter for this.
327        static const float shrink_load = shrink_load_pm / 1000.0f;
328        static const float perfect_load = perfect_load_pm / 1000.0f;
329        static const float grow_load = grow_load_pm / 1000.0f;
330
331        /**
332         */
333//      __attribute__((noinline))
334        static bool need_grow( size_t elements, size_t slots )
335        {
336                // XXX A later design could sacrifice a few bytes to store the actual
337                // values in elements for grow and shrink barriers, so that a check
338                // against those only needs to compare against them. Of course in case
339                // of a real resize event those values will need to be recalculated.
340                // Since this is a speed vs space trade-off we will provide template
341                // parameters for that with proper defaults.
342
343                // calculate actual load factor
344                double lfactor = double(elements)/slots;
345#ifdef DEBUG
346                std::cerr << "need_grow load factor " << lfactor << "\n";
347                std::cerr << "load factor at which to start growing " << grow_load << "\n";
348                std::cerr << "returning " << ( lfactor >= grow_load ) << "\n";
349#endif
350                if( lfactor >= grow_load )
351                {
352                        return true;
353                }
354                else
355                {
356                        return false;
357                }
358        }
359
360        static bool need_shrink( size_t elements, size_t slots )
361        {
362                // calculate actual load factor
363                // XXX Check whether the compiler can properly inline and elide this
364                // calculation in the case need_resize() will be called.
365                double lfactor = double(elements)/slots;
366#ifdef DEBUG
367                std::cerr << "need_shrink load factor " << lfactor << "\n";
368                std::cerr << "load factor at which to start shrinking " << shrink_load << "\n";
369                std::cerr << "returning " << ( lfactor < shrink_load ) << "\n";
370#endif
371                if( lfactor < shrink_load )
372                {
373                        return true;
374                }
375                else
376                {
377                        return false;
378                }
379        }
380
381        static bool need_resize( size_t elements, size_t slots )
382        {
383                return need_grow(elements,slots) || need_shrink(elements,slots);
384        }
385
386};
387
388template<
389int grow_load_pm,
390int perfect_load_pm,
391int shrink_load_pm,
392size_t* prime_table_start,
393size_t prime_table_size
394>
395struct resize_primetable_template
396        : resize_base<grow_load_pm,perfect_load_pm, shrink_load_pm>
397{
398        typedef resize_base<grow_load_pm,perfect_load_pm, shrink_load_pm> base_type;
399
400        typedef slot_selector_modulo slot_selector;
401
402        static size_t max_size( )
403        {
404                return prime_table_start[prime_table_size-1];
405        }
406        /**
407         * The optimal size will be calculated in the way that from the desired
408         * load factor (per default 0.8*elements) on we will take the next bigger
409         * prime from our table. The table was generated using a start number (89)
410         * and multiplying this by 1.5 and then choosing the next prime (and so on,
411         * taking the previous result and not the prime as input for multiplication
412         * by 1.5 so that you can easier determine the numbers).
413         * @note the optimal_size function is potentially expensive and should only
414         * be called in the case a resize needs to be done. Determining whether a
415         * resize is needed should be done purely on the current sizes load factor.
416         */
417        static size_t optimal_size( size_t elements )
418        {
419                // First of all we calculate the number of slots for the desired
420                // perfect load factor.
421                size_t min_slots = elements / base_type::perfect_load;
422                // then search in the provided primetable for a proper prime number.
423                size_t* i = std::lower_bound(prime_table_start, prime_table_start + prime_table_size , min_slots);
424                if( i == (prime_table_start+prime_table_size) )
425                {
426                        // XXX refine to a more suited exception type one day
427                        throw std::runtime_error("Exceeded built in primetable while generating optimal_size");
428                }
429                return *i;
430        }
431
432        static bool need_resize( size_t elements, size_t slots )
433        {
434                return (base_type::need_grow(elements,slots) || base_type::need_shrink(elements,slots))
435                        // actually ask for shrink only if the amount of elements is really
436                        // bigger than the smallest size we would ever have.
437                        && prime_table_start[0] < elements;
438        }
439
440
441};
442
443template<
444int grow_load_pm = 800,
445int perfect_load_pm = 700,
446int shrink_load_pm = 300
447>
448struct resize_primetable_15
449        : resize_primetable_template<grow_load_pm,perfect_load_pm, shrink_load_pm,primetable15,asize(primetable15)>
450{
451};
452
453
454// XXX A good default load factor depends on the collision resolution used
455template<
456int grow_load_pm = 800,
457int perfect_load_pm = 700,
458int shrink_load_pm = 300
459>
460struct resize_power2
461        : resize_base<grow_load_pm, perfect_load_pm, shrink_load_pm>
462{
463        typedef resize_base<grow_load_pm, perfect_load_pm, shrink_load_pm> base_type;
464
465        typedef slot_selector_power2 slot_selector;
466
467        static size_t max_size( )
468        {
469                return static_cast<size_t>(-1);
470        }
471        /**
472         *
473         */
474        static size_t optimal_size( size_t elements )
475        {
476                // the optimal size is given a certain load factor the next power of
477                // two after the amount of slots needed to achieve this load factor.
478                size_t min_slots = elements / base_type::perfect_load;
479                // Now find the next power of two...
480                size_t s = __detail::roundup2(min_slots);
481                return s;
482        }
483};
484
485struct raw_pointer
486{
487        template<class T>
488        struct pointer
489        {
490                typedef T* type;
491        };
492};
493
494
495
496// generic anchor hierarchy, to be used by all possible containers that might
497// want to use them.
498
499template<class T, class PTR_SELECTOR >
500struct anchor_single
501{
502        typedef T item_type;
503        typedef typename PTR_SELECTOR::template pointer<item_type>::type pointer_type;
504        typedef decltype(*pointer_type()) reference_type;
505
506        static const bool empty = false;
507protected:
508        pointer_type next;
509public:
510        anchor_single( )
511                : next(0) // not really necessary but gcc warns otherwise
512        {
513#ifdef DEBUG
514                next = reinterpret_cast<pointer_type>(~0UL);
515#endif
516        }
517
518        const pointer_type get_next() const { return next; }
519        pointer_type get_next() { return next; }
520        void set_next( pointer_type ptr ) { next = ptr; }
521};
522
523template<class T, class PTR_SELECTOR>
524struct anchor_double : public anchor_single<T,PTR_SELECTOR>
525{
526    typedef anchor_single<T,PTR_SELECTOR> base_type;
527    typedef typename base_type::item_type item_type;
528    typedef typename base_type::pointer_type pointer_type;
529    typedef typename base_type::reference_type reference_type;
530protected:
531    pointer_type prev;
532public:
533    const pointer_type get_prev() const { return prev; }
534    void set_prev( pointer_type ptr ) { prev = ptr; }
535};
536
537template<class T, class PTR_SELECTOR>
538struct anchor_btree : protected anchor_double<T,PTR_SELECTOR>
539{
540    typedef anchor_double<T,PTR_SELECTOR> base_type;
541    typedef typename base_type::item_type item_type;
542    typedef typename base_type::pointer_type pointer_type;
543    typedef typename base_type::reference_type reference_type;
544
545    const pointer_type get_left() const { return base_type::prev; }
546    const pointer_type get_right() const { return base_type::next; }
547
548    void set_left( pointer_type ptr ) { base_type::set_prev(ptr); }
549    void set_right( pointer_type ptr ) { base_type::set_next(ptr); }
550
551    base_type& get_base() { return *this; } 
552    const base_type& get_base() const { return *this; } 
553};
554
555namespace avl
556{
557    enum class skew
558    {
559        none,
560        left,
561        right
562    };
563}
564
565/* need to be adapted to new PTR_SELECTOR non-template variant
566template<class T, template<class> class PTR>
567struct anchor_avltree : public anchor_btree<T,PTR>
568{
569    avl::skew sk;
570    avl::skew get_skew() const { return sk; }
571    void set_skew( avl::skew _sk ) { sk = _sk; }
572};
573
574template<class T, template<class> class PTR>
575struct anchor_compressed_avltree : public anchor_btree<T,PTR>
576{
577    typedef anchor_btree<T,PTR> base_type;
578    typedef typename base_type::item_type item_type;
579    typedef typename base_type::pointer_type pointer_type;
580    typedef typename base_type::reference_type reference_type;
581
582    // XXX its likely a good idea to have this as a free utility function somewhere
583    static ptrdiff_t get_pointer_bits( const void* ptr, ptrdiff_t mask )
584    {
585        const char* t = reinterpret_cast<const char*>(ptr);
586        const char* null = 0;
587        ptrdiff_t d = t - null;
588        return (d&mask);
589    }
590    // abuse boost::mpl::print to emit a warning when sizeof(base) != sizeof(*this)
591        avl::skew get_skew() const
592        {
593                // for efficiency reasons, if possible we only use the left pointer
594                if( sizeof(*this) >= 4 )
595                {
596                        // pointer points always to a multiple of 4, meaning that the lower
597                        // two bits are reserved for us. Useful compilers will eliminate
598                        // this if.
599                        return static_cast<avl::skew>( get_pointer_bits(get_left(), 0x3u));
600                }
601                else
602                {
603                        const ptrdiff_t mask = 0x1u;
604                        assert( sizeof(*this) >= 2 ); // it cannot be lower, we consist of two distinct objects, that is pointers
605                        if( get_pointer_bits(get_left(),mask) ) // lowest bit of left is set
606                        {
607                                assert( !get_pointer_bits(get_right() & mask) ); // both bits are never set by us, so this must be a bug somewhere
608                                return avl::skew::left;
609                        }
610                        else if( get_pointer_bits(get_right(),mask) ) // lowest bit of left is set
611                        {
612                                assert( !get_pointer_bits(get_left() & mask) ); // both bits are never set by us, so this must be a bug somewhere
613                                return avl::skew::right;
614                        }
615                        // no bit is set, skew is none
616                        return avl::skew::none;
617                }
618        }
619
620    void set_skew( avl::skew _sk );
621
622    // XXX its likely a good idea to have this as a free utility function somewhere
623        template<class U>
624        U* get_masked_pointer( const void* ptr, ptrdiff_t mask )
625        {
626                U* ret;
627                const char* t = reinterpret_cast<const char*>(ptr);
628                const char* null = 0;
629                ptrdiff_t d = t - null;
630                d &= ~mask; // mask "off" the bits
631                ret = static_cast<U*>(null + d);
632                return ret;
633        }
634
635    const pointer_type get_left() const
636    {
637        if( sizeof(*this) >= 4 )
638        {
639            return get_masked_pointer<const pointer_type>(base_type::get_left(),0x3u);
640        }
641        else
642        {
643            return get_masked_pointer<const pointer_type>(base_type::get_left(),0x1u);
644        }
645    }
646
647    const pointer_type get_right() const
648    {
649        if( sizeof(*this) >= 4 )
650        { // in this case, the right pointer is not used for special bits
651            return base_type::get_right();
652        }
653        else
654        { // in this case, its the lowest bit, mask it off
655            return get_masked_pointer<const pointer_type>(base_type::get_right(),0x1u);
656        }
657    }
658
659    void set_left( pointer_type ptr )
660    {
661        // XXX We should make this function act upon the actual skew and
662        // sizeof(*this) and maybe change the skew only if affected by the
663        // pointer or so.
664        avl::skew s = get_skew();
665        base_type::set_left(ptr);
666        set_skew(s);
667    }
668
669    void set_right( pointer_type ptr )
670    {
671        avl::skew s = get_skew();
672        base_type::set_right(ptr);
673        set_skew(s);
674    }
675};
676*/
677
678enum class occupancy : unsigned char
679{
680        free,
681        deleted,
682        occupied
683};
684
685template<bool>
686struct anchor_occupancy_storage;
687
688template<>
689struct anchor_occupancy_storage<true>
690{
691        occupancy occupied;
692};
693
694template<>
695struct anchor_occupancy_storage<false>
696{
697};
698
699template<bool>
700struct anchor_hash_storage;
701
702template<>
703struct anchor_hash_storage<true>
704{
705        size_t hash;
706};
707
708template<>
709struct anchor_hash_storage<false>
710{
711};
712
713template<class anchor_type, bool empty>
714struct anchor_storage;
715
716template<class anchor_type>
717struct anchor_storage<anchor_type,false>
718{
719        anchor_type anchor;
720};
721
722template<class anchor_type>
723struct anchor_storage<anchor_type,true>
724{
725};
726
727template< class anchor_type, bool store_hash, bool store_occupancy>
728struct anchor_member_mixer :
729        anchor_storage<anchor_type, anchor_type::empty>,
730        anchor_occupancy_storage<store_occupancy>,
731        anchor_hash_storage<store_hash>
732
733{
734};
735
736template<class ANCHOR_ACCESSOR>
737struct single_inserter_template
738{
739        typedef ANCHOR_ACCESSOR anchor_accessor;
740
741        template<class AA>
742        struct rebind
743        {
744                typedef single_inserter_template<AA> other;
745        };
746
747        // XXX choose per template parameter whether to put things at the beginning
748        // or the end of the list
749        template<
750                class IT,
751                class SZ,
752                class SLA
753                >
754        static bool insert( IT* i, SZ idx, SLA** sa )
755        {
756                SLA*& slot = sa[idx];
757#ifdef DEBUG
758                std::cerr << "Chosen slot = " << (void*)slot << "\n";
759#endif
760                anchor_accessor aa;
761                aa(i)->anchor.set_next(0);
762                // XXX if is_occupied(slot) for others
763                if( slot )
764                {
765                        IT* next = slot;
766                        while( aa(next)->anchor.get_next() )
767                        {
768#ifdef DEBUG
769                                std::cerr << "Accessing slot/item " << (void*)slot << " and next being ";
770#endif
771                                next = aa(next)->anchor.get_next();
772#ifdef DEBUG
773                                std::cerr << (void*)next << "\n";
774#endif
775                        }
776                        assert( next != NULL );
777                        // next now contains the last item in the list
778                        // XXX singly linked list collision resolution
779                        aa(next)->anchor.set_next(i);
780                }
781                else // its free, just set it
782                {
783                        slot = i;
784                }
785                return true;
786        }
787
788        template<
789                class IT,
790                class SZ,
791                class SLA
792                >
793        static bool remove( IT* it, SZ idx, SLA** sa )
794        {
795                SLA*& slot = sa[idx];
796                anchor_accessor aa;
797                if( slot == it )
798                {
799                        // If it is directly sitting at the slot remove it there.
800                        slot = aa(it)->anchor.get_next();
801#ifdef DEBUG
802                        aa(it)->anchor.set_next( reinterpret_cast<IT*>(~0UL) );
803#endif
804                        return true;
805                }
806                else if( slot )
807                {
808                        // It is not the first in the slot but there is something
809                        IT* next = slot;
810                        while( aa(next)->anchor.get_next() )
811                        {
812                                IT* prev = next;
813                                next = aa(next)->anchor.get_next();
814                                if( next == it )
815                                {
816                                        aa(prev)->anchor.set_next( aa(next)->anchor.get_next() );
817#ifdef DEBUG
818                                        aa(next)->anchor.set_next( reinterpret_cast<IT*>(~0UL) );
819#endif
820                                        return true;
821                                }
822                        }
823
824                }
825                return false;
826        }
827
828};
829
830template<class ANCHOR_ACCESSOR>
831struct double_inserter_template
832{
833        typedef ANCHOR_ACCESSOR anchor_accessor;
834
835        template<class AA>
836        struct rebind
837        {
838                typedef double_inserter_template<AA> other;
839        };
840
841        template<
842                class IT,
843                class SZ,
844                class SLA
845                >
846        bool operator()( IT* i, SZ idx, SLA** sa )
847        {
848                SLA*& slot = sa[idx];
849#ifdef DEBUG
850                std::cerr << "Chosen slot = " << (void*)slot << "\n";
851#endif
852                // XXX if is_occupied(slot) for others
853                if( slot )
854                {
855                        anchor_accessor aa;
856                        IT* next = slot;
857                        while( aa(next)->get_next() )
858                        {
859#ifdef DEBUG
860                                std::cerr << "Accessing slot/item " << (void*)slot << " and next being ";
861#endif
862                                next = aa(next)->get_next();
863#ifdef DEBUG
864                                std::cerr << (void*)next << "\n";
865#endif
866                        }
867                        // next now contains the last item in the list
868                        // XXX singly linked list collision resolution
869                        aa(next)->set_next(i);
870                        aa(i)->set_next(0);
871//                      ++elem_size;
872                }
873                else // its free, just set it
874                {
875                        slot = i;
876//                      ++elem_size;
877                }
878                return true;
879        }
880};
881
882struct double_inserter
883{
884        template<class AA>
885        struct rebind
886        {
887                typedef double_inserter_template<AA> other;
888        };
889};
890
891struct single_inserter
892{
893        template<class AA>
894        struct rebind
895        {
896                typedef single_inserter_template<AA> other;
897        };
898};
899
900
901struct resolution_single_linked_list
902{
903        template<class T, class PTR_SELECTOR>
904        struct anchor_member_type
905        {
906                typedef anchor_single<T,PTR_SELECTOR> type;
907        };
908        typedef single_inserter inserter;
909};
910
911
912/**
913 * This is a metafunction that provides the proper type for an anchor, given
914 * certain parameters.
915 * @tparam COLLISION_RESOLUTION is the metafunction that provides the way
916 * collisions are resolved. Depending on that the anchor may contain pointers
917 * (e.g. for linked list resolves) or also simply nothing.
918 * @tparam PTR_SELECTOR is the selector metafunction that transforms types into
919 * pointers to that type. We use it everywhere so that we can use special
920 * pointer types (shared pointers, relative pointers etc.)
921 * @tparam store_occupancy tells us whether we should provide storage for
922 * whether this item is occupied or not. This makes only sense if you want to
923 * use an open addressing hashtable, as such the collision resolution should be
924 * chosen in an appropriate way.
925 * @tparam store_hash tells us whether the hash value is ever stored or not. If
926 * it is stored, then it will be in a member of type size_t.
927 */
928template<
929class T,
930class COLLISION_RESOLUTION = resolution_single_linked_list ,
931class PTR_SELECTOR = raw_pointer,
932bool store_hash = false,
933bool store_occupancy = false
934>
935struct anchor_member_chooser
936{
937        typedef 
938                anchor_member_mixer<
939                typename COLLISION_RESOLUTION::template anchor_member_type<T,PTR_SELECTOR>::type,
940                store_hash,
941                store_occupancy>
942                type;
943};
944
945// ############################################# # # # # # # # # # # # # # # # # # # # # # # # #
946//
947// We do not want the user to manually chose (however he of course can do so)
948// the necessary anchor for his hash table, but we want to provide a
949// metafunction that can do so. Therefore we create here something that
950// collects all the properties for the future hashtable that will not depend on
951// the type of data being stored. Within that embedded will be a metafunction
952// that chooses the anchor type.
953// Those marked with * influence the anchor type
954//
955// Not all of these things may be combined
956//*- collision resolution scheme
957//   - single linked list
958//   - double linked list
959//   - jumping (various weird kinds)
960//   - rehashing (various ways, including one with alternative hashers)
961//   - cookoo hashing
962// - allocator storage
963//   - whether to store the allocator passed to the ctor in a member variable or not
964// - comparator storage
965//   - whether to store the comparator passed to the ctor in a member variable or not
966//*- data storage
967//   - in the table (OA like), item will be copied (precludes linked list et al collision resolution)
968//   - as pointers, items will be "linked" into the datastructure
969//*- pointer type
970//   - default is a raw pointer
971//   - metafunction that will lead to a pointer type when fed with T
972//*- store hash
973//   - storing the hash (without the upper bit) set might be necessary in case
974//     the hashing is so expensive that its worth it
975// - ownership
976//   - data structure owns data (on destruction, all items are destroyed)
977//   - the user owns the data. On destruction, items will not be touched at all
978// - size and access
979//   - size is always multiple of 2, access to slots is done by masking of bits
980//   - size is an arbitrary number (likely prime). slots will be chosen by
981//     taking the remainder of division modulo the size
982// - table storage
983//   - default is std::vector
984//   - a metafunction or template can be provided that will determine the type
985//     of the underlying table storage.
986// - the size_type
987//   - type that is used to store various underlying values
988// - automatic resize on insert/remove.
989//   - enable per template
990//   - disable per template
991//   - have a runtime changeable flag with templated default
992// - duplicate entries
993//   - allow/disallow per template parameter
994// - compare hash
995//   - if store hash is enabled, before comparing the elements themselves, the hash is compared
996// - allocator and storage
997//   - an allocator must be specified which can be stored optionally, have a param that tells us
998// - same for a comparator
999// - also for the hasher we might want to store it (or not)
1000// The result must be in the hash_config passed to the hash_table
1001// ############################################# # # # # # # # # # # # # # # # # # # # # # # # #
1002// For the following things, we need to have T available in some way.
1003// - hashing
1004//   - user provides a functor or metafunction or whatever that can hash T into
1005//     an integer
1006//   - We provide means for hashing standard datastructures and arbitrary byte
1007//     buffers in three categories, among the user could chose for his datatypes too.
1008//       - identity. Do not hash things, useful for those cases where the key
1009//         is known to be distributed properly
1010//       - trivial is a very simple way to determine the hash
1011//       - fnv uses a bit more complex hashing, similar to fnv
1012// - anchor access
1013//   - the user provides a mean for accessing the appropriate anchor for this
1014//     hashtable when having a T* at hand
1015//   - for OA-like hashtables that store copies in the table itself, the anchor
1016//     shall provide a way to mark items as occupied, free or deleted. Each
1017//     element *must* be default constructible and *must* be initially marked
1018//     as free. Failure to do so will lead to undefined behaviour
1019// The result must be in the hash_accessor passed to the hash_table
1020namespace collision_resolution
1021{
1022
1023/**
1024 * This shall resolve collisions by putting things in a singly linked list.
1025 * We gonna need functionality for specifying the type of the anchor and a
1026 * function to resolve things in case of a collision. Lets start with simple
1027 * ones and adapt the interface for every of them.
1028 */
1029#if 0
1030template<
1031class T,
1032class POINTER_TYPE,
1033class ANCHOR_ACCESSOR
1034>
1035struct resolve_single_linked
1036{
1037        typedef T item_type;
1038        typedef POINTER_TYPE<item_type>::type pointer_type;
1039        typedef anchor_single<T,POINTER_TYPE> anchor_type;
1040        typedef ANCHOR_ACCESSOR<anchor_type> anchor_accessor;
1041
1042        /**
1043         * @param colliding is the element at the slot where the collision has been detected.
1044         * @param added is the element that shall be added to the hashtable. After
1045         * returning, this element is a successful member of the hashtable.
1046         */
1047        static void resolve( T* colliding, T* added )
1048        {
1049                T* nx = colliding;
1050                T* tmp;
1051                while(tmp = anchor_accessor::get(nx).get_next())
1052                {
1053                        nx = tmp;
1054                }
1055                anchor_accessor::get(nx).set_next(added);
1056                anchor_accessor::get(added).set_next(0);
1057        }
1058
1059        struct iterator
1060        {
1061                pointer_type* slot_position;
1062                pointer_type item;
1063                iterator& operator++(int);
1064                iterator& operator++();
1065        };
1066};
1067#endif
1068
1069}
1070
1071#if 0
1072template<
1073class T,
1074template<class,class> class COLLISION_RESOLUTION,
1075template<class,class> class DATA_ACCESS,
1076template<class> class POINTER_TYPE
1077      >
1078struct hash_intrusion_config // weird name but for OA style we don't have any anchor...
1079{
1080        /**
1081         * Just define the type of the object that shall be stored
1082         */
1083        typedef T item_type;
1084
1085        /**
1086         * Metafunction that transforms any item type into the pointer type
1087         * We leave this as a metafunction and do not directly use a pointer type
1088         * since maybe at other places we need pointers too but have some different
1089         * item type. Just be flexible.
1090         */
1091        template<class IT>
1092        struct pointer_type
1093        {
1094                typedef typename POINTER_TYPE<IT>::type type;
1095        };
1096
1097        /**
1098         * This should somehow resemble the slot type. It will depend on the actual
1099         * planned collision resolution and also on where to store what, usually
1100         * its though either the element itself or a pointer to it.
1101         */
1102        template<class IT>
1103        struct slot_type
1104        {
1105        };
1106
1107        /*
1108         * anchor type depends on collision resolution. If its single/double linked
1109         * list then we have anchors, if its some re-hashing or OA we just have
1110         * nothing. Ideally the anchor would not eixst then giving us compile time
1111         * errors.
1112         */
1113        typedef typename COLLISION_RESOLUTION<T,
1114                        STORE_HASH,
1115                        POINTER_TYPE
1116                        >::anchor_type anchor_type;
1117};
1118#endif
1119
1120template<
1121class T0,
1122class T1,
1123class T2,
1124class T3,
1125class T4,
1126class T5
1127      >
1128struct hash_config
1129{
1130};
1131
1132// Here we wrap the storage type that the user wants us to use in a hashtable
1133template<class T>
1134struct storage_wrapper
1135{
1136};
1137
1138template<class A>
1139struct anchor_accessor_single
1140{
1141    typedef typename A::item_type item_type;
1142    A* operator()( item_type* i )
1143    {
1144        // XXX This all is total mockup, we really need a way to
1145        // flexibly accessing the proper member (possible via member
1146        // pointers). This interface must be suitable for the
1147        // generated item types from UDTs.
1148        return &(i->anchor); // XXX make this a refernece
1149    }
1150};
1151
1152#if 0
1153template<class T>
1154struct hash_anchor_oa
1155{
1156    /**
1157     * To mark this element as occupied/free/deleted
1158     */
1159    unsigned char status;
1160};
1161
1162template<class T>
1163struct hash_item_double
1164{
1165    typedef T item_type;
1166    hash_anchor_double<T> anchor;
1167    T item;
1168};
1169
1170/**
1171 * There is no real anchor for OA based items. Either we have just a plain
1172 * pointer to them or they are already fully in the table.
1173 */
1174template<class T>
1175struct hash_item_oa
1176{
1177    typedef T item_type;
1178};
1179
1180template<class T>
1181struct hash_item_single
1182{
1183    typedef T item_type;
1184    hash_anchor_single<T> anchor;
1185    T item;
1186};
1187
1188/**
1189 * For open addressing based hashtables there is the possibility of using this
1190 * only as collision resolution, and just store the pointers in there, or to
1191 * store the whole object in there. This is the variant of the item thats just
1192 * for the pointers.
1193 */
1194template<class T>
1195struct hash_item_oa_pointer
1196{
1197    typedef T item_type;
1198    item_type* item;
1199};
1200
1201template<class T>
1202struct hash_item_oa_item
1203{
1204    typedef T item_type;
1205    item_type item;
1206};
1207#endif
1208/**
1209 * This class controls how the single items that are being stored in the table
1210 * are accessed.
1211 * If there is no special accessor that uses anchors embedded in the usertype,
1212 * then this will generate nodes containing the users type in them and all
1213 * inserts will be copies instead of "hanging" the node into the table.
1214 */
1215template<class T>
1216struct hash_accessor
1217{
1218    typedef typename T::item_type item_type;
1219
1220};
1221
1222template<bool store_per_instance, class H>
1223struct hasher_storage_base;
1224
1225template<class H>
1226struct hasher_storage_base<true,H>
1227{
1228        H hasher_instance;
1229};
1230
1231template<class H>
1232struct hasher_storage_base<false,H>
1233{
1234        static H hasher_instance;
1235};
1236
1237template<class H>
1238H hasher_storage_base<false,H>::hasher_instance;
1239
1240template<bool store_per_instance, class H>
1241struct allocator_storage_base;
1242
1243template<class H>
1244struct allocator_storage_base<true,H>
1245{
1246        H allocator_instance;
1247};
1248
1249template<class H>
1250struct allocator_storage_base<false,H>
1251{
1252        static H allocator_instance;
1253};
1254
1255template<class H>
1256H allocator_storage_base<false,H>::allocator_instance;
1257
1258template<
1259class T,
1260class ATYPE,
1261ATYPE T::* AMEMBER
1262>
1263struct anchor_member_accessor
1264{
1265        ATYPE* operator()( T& t ) { return &( t.*AMEMBER); }
1266        ATYPE* operator()( T* t ) { return &( t->*AMEMBER); }
1267};
1268
1269template<class T>
1270struct item_compare
1271{
1272        bool operator()( const T& l, const T& r ) const
1273        {
1274                return l == r;
1275        }
1276};
1277
1278template< class T , class K , K T::* M >
1279struct member_compare
1280{
1281        template<class R>
1282        bool operator()( const T& l, const R& r ) const
1283        {
1284                return l.*M == r;
1285        }
1286
1287        bool operator()( const T& l, const T& r ) const
1288        {
1289                return l.*M == r.*M;
1290        }
1291
1292};
1293struct auto_size_always
1294{
1295        bool auto_size( ) const { return true; }
1296};
1297
1298struct auto_size_never
1299{
1300        bool auto_size( ) const { return false; }
1301};
1302
1303struct empty_base_owns
1304{
1305};
1306
1307struct empty_base_size
1308{
1309};
1310
1311
1312enum class storage_levels
1313{
1314        storage_level_auto_size,
1315        storage_level_owns_items
1316};
1317
1318struct auto_size_bool_storage
1319{
1320        bool a_size;
1321
1322        template<int>
1323        void store( bool b )
1324        {
1325                a_size = b;
1326        }
1327
1328        template<int>
1329        bool load( void ) const
1330        {
1331                return a_size;
1332        }
1333};
1334
1335struct owns_items_bool_storage
1336{
1337        bool o_items;
1338
1339        template<int>
1340        void store( bool b )
1341        {
1342                o_items = b;
1343        }
1344
1345        template<int>
1346        bool load( void ) const
1347        {
1348                return o_items;
1349        }
1350};
1351/**
1352 * important: This must always go at least once through rebind to make the
1353 * mpl::if_c call so the use_bitset_storage parameter is reflected correctly.
1354 */
1355template<bool def = true, bool use_bitset_storage = true, class T = void >
1356struct auto_size_runtime
1357        : public boost::mpl::if_c<use_bitset_storage,empty_base_size,auto_size_bool_storage>::type
1358{
1359        auto_size_runtime( )
1360        {
1361                set_auto_size(def);
1362        }
1363
1364        static const storage_levels storage_level = storage_levels::storage_level_auto_size;
1365
1366        static const bool needs_bitset_storage = use_bitset_storage;
1367
1368        void set_auto_size( bool en = true)
1369        {
1370                static_cast<T*>(this)->template store<storage_level>(en);
1371        }
1372
1373        bool auto_size( ) const
1374        {
1375                return static_cast<const T*>(this)->template load<storage_level>();
1376        }
1377
1378        template<class U>
1379        struct rebind
1380        {
1381                typedef auto_size_runtime<def,use_bitset_storage,
1382                        typename boost::mpl::if_c<use_bitset_storage, U, auto_size_bool_storage>::type > other;
1383        };
1384};
1385
1386template<bool def = true, bool use_bitset_storage = true, class T = void >
1387struct owns_items_runtime
1388        : public boost::mpl::if_c<use_bitset_storage,empty_base_owns,owns_items_bool_storage>::type
1389{
1390        owns_items_runtime( )
1391        {
1392                set_owns_items(def);
1393        }
1394
1395        static const storage_levels storage_level = storage_levels::storage_level_owns_items;
1396
1397        static const bool needs_bitset_storage = use_bitset_storage;
1398
1399        void set_owns_items( bool en = true)
1400        {
1401                static_cast<T*>(this)->template store<storage_level>(en);
1402        }
1403
1404        bool owns_items( ) const
1405        {
1406                return static_cast<const T*>(this)->template load<storage_level>();
1407        }
1408
1409        template<class U>
1410        struct rebind
1411        {
1412                typedef owns_items_runtime<def,use_bitset_storage,
1413                        typename boost::mpl::if_c<use_bitset_storage, U, owns_items_bool_storage>::type > other;
1414        };
1415};
1416
1417
1418
1419template<class T0, class T1>
1420struct policy_bool_storage :
1421        T0::template rebind<policy_bool_storage<T0,T1> >::other,
1422        T1::template rebind<policy_bool_storage<T0,T1> >::other
1423{
1424        bool b0 : 1;
1425        bool b1 : 1;
1426
1427        template<unsigned N>
1428        void store( bool b )
1429        {
1430                switch(N)
1431                {
1432                        case 0:
1433                                b0 = b;
1434                                break;
1435                        case 1:
1436                                b1 = b;
1437                                break;
1438                        // intentionally no default case, anything else here is UB
1439                }
1440        }
1441
1442        template<unsigned N>
1443        bool load( void ) const
1444        {
1445                switch(N)
1446                {
1447                        case 0:
1448                                return b0;
1449                        case 1:
1450                                return b1;
1451                }
1452        }
1453};
1454
1455struct three_bytes_test
1456{
1457        char c0;
1458        char c1;
1459        char c2;
1460};
1461#if 0
1462// planned final class interface something like:
1463hash_table<T,ACCESSOR,HASHER,
1464        store_hasher<true>,
1465        equal_comparator<COMPARE>,
1466        size_type<int>,
1467        auto_size<auto_size_runtime<false> >,
1468
1469#endif
1470
1471template<bool STORE_MASK, class SIZE_TYPE, class SLOT_RESIZER>
1472struct mask_storage_base;
1473
1474template<class SIZE_TYPE, class SLOT_RESIZER>
1475struct mask_storage_base<true,SIZE_TYPE,SLOT_RESIZER>
1476{
1477        typedef SLOT_RESIZER slot_resizer;
1478        typedef typename slot_resizer::slot_selector hash_slot_selector;
1479        typedef SIZE_TYPE size_type;
1480
1481        size_type h_mask;
1482
1483        void reset_mask( size_t len )
1484        {
1485                h_mask = hash_slot_selector::mask_from_length(len);
1486        }
1487
1488        size_type hash_mask( size_t /*len*/ ) const
1489        {
1490                return h_mask;
1491        }
1492};
1493
1494template<class SIZE_TYPE, class SLOT_RESIZER>
1495struct mask_storage_base<false,SIZE_TYPE,SLOT_RESIZER>
1496{
1497        typedef SLOT_RESIZER slot_resizer;
1498        typedef typename slot_resizer::slot_selector hash_slot_selector;
1499        typedef SIZE_TYPE size_type;
1500
1501        void reset_mask( size_t /*len*/ )
1502        {
1503        }
1504
1505        size_type hash_mask( size_t len ) const
1506        {
1507                return hash_slot_selector::mask_from_length(len);
1508        }
1509};
1510
1511/**
1512 */
1513template<class T
1514, class SIZE_TYPE
1515, class HASHER
1516, bool STORE_HASHER
1517, bool STORE_MASK
1518, class SLOT_RESIZER
1519, class ANCHOR_ACCESSOR
1520, class COMPARE
1521, class INSERTER
1522, class AUTOSIZE
1523, class OWNAGE
1524    >
1525class hash_table :
1526        protected hasher_storage_base<STORE_HASHER,HASHER>,
1527        protected mask_storage_base<STORE_MASK,SIZE_TYPE,SLOT_RESIZER>,
1528//      protected allocator_storage_base<STORE_ALLOCATOR,ALLOCATOR>
1529        // XXX MPL check for whether we do not better derive from empty base
1530        public policy_bool_storage<AUTOSIZE, OWNAGE>
1531        // XXX later check how many size_type members we have at most and at least.
1532        // If this differs much, and they are also shattered around then it could
1533        // make sense to do something like the policy_bool_storage for size_type so
1534        // that alignment issues due to derivation do not play any role.
1535{
1536public:
1537        typedef policy_bool_storage<AUTOSIZE, OWNAGE> pbstorage;
1538    /**
1539     * This is the selector type that will give us many mayn informations about
1540     * other types.
1541     */
1542//    typedef S hash_selector;
1543
1544    /**
1545     * This is the type of the items or "nodes" that the user will put into our
1546     * hashtable. Depending on the selector, our array will contain those items
1547     * explicitly, or pointers to them, that then will either resemble singly
1548     * linked or doubly linked lists.
1549     */
1550    typedef T item_type;
1551
1552        typedef SIZE_TYPE size_type;
1553        typedef item_type* slot_item_type;
1554//      typedef std::vector<slot_item_type> table_type;
1555        typedef slot_item_type* table_type;
1556
1557        typedef SLOT_RESIZER slot_resizer;
1558        typedef typename slot_resizer::slot_selector hash_slot_selector;
1559        typedef ANCHOR_ACCESSOR anchor_accessor;
1560
1561        typedef COMPARE compare;
1562
1563//      typedef INSERTER inserter;
1564        typedef typename INSERTER::template rebind<ANCHOR_ACCESSOR>::other inserter;
1565
1566
1567//    typedef typename hash_selector::size_type size_type;
1568//    typedef K key_type;
1569//    typedef typename hash_selector::template slot_item<item_type>::type slot_item_type;
1570//    typedef typename hash_selector::template add_pointer<slot_item_type>::type table_type;
1571
1572    /**
1573     * We are a nullary metafunction returning ourselves. Who knows what this
1574     * is good for...
1575     */
1576    typedef hash_table type;
1577//    typedef V<slot_item_type> sequence_type;
1578//    typedef IT iterator;
1579//    typedef IT const_iterator;
1580 /*   template<class T,...>
1581    struct
1582    {
1583        typedef hash_table<T,...> type;
1584    } helper_type;
1585    */
1586private:
1587        table_type data;
1588
1589        /**
1590         * Amount of elements actually contained within the hashtable.
1591         */
1592        size_type elem_size;
1593
1594        /**
1595         * The length of the slots array/vector.
1596         */
1597        size_type h_length;
1598
1599protected:
1600public:
1601        hash_table( size_type i_s ) :
1602                elem_size(0)
1603        {
1604                h_length = slot_resizer::optimal_size(i_s);
1605                data = new slot_item_type[h_length];
1606                // XXX This fill is redundant if the slot item type is a UDT. It makes
1607                // only sense if it is a pointer type.
1608                std::fill_n( data, h_length, slot_item_type());
1609                this->reset_mask(table_size());
1610#ifdef DEBUG
1611                std::cerr << "i_s = " << i_s << ", h_length " << h_length << ", h_mask = " << this->hash_mask(table_size()) << "\n";
1612#endif
1613        }
1614
1615        /* currently broken, recreate as soon as the above ctor is stable and we
1616         * can provide useful defaults here.
1617         * XXX Make sure empty hashtables work well with no dynamic storage
1618         * allocated. (especially iterators etc. will have to work properly)
1619        hash_table( ) :
1620                data(0),
1621                elem_size(0),
1622                h_mask(0)
1623        {
1624        }
1625        */
1626
1627        ~hash_table( )
1628        {
1629                // XXX allocation and deallocation should be routed through a policy so
1630                // we can use policies that allocate in e.g. memory mapped files using
1631                // relative pointers.
1632                clear();
1633                delete[] data;
1634        }
1635
1636        hash_table( const hash_table& ) = delete;
1637        hash_table& operator=( const hash_table& ) = delete;
1638
1639    // insert variant that allows duplicates and uses single linked lists for
1640    // collision resolution.
1641    /**
1642     * @returns true if the insert was successfully, the item should be removed
1643     * from the structure prior to deletion, as removing will likely need
1644     * access to the item. If false is returned, this means that the item has
1645     * not been inserted. In this case the user is always responsible for
1646     * handling this item, e.g. delete it.
1647     */
1648//    IWEAR_WARN_UNUSED_RESULT
1649        bool insert( item_type* i )
1650        {
1651                // XXX note: a shrink on insert doesn't really make sense. If the table
1652                // is bigger then it is because someone has removed something without
1653                // having the table shrink, or its being constructed to hold many
1654                // elements.
1655                if( maybe_grow() )
1656                {
1657#ifdef DEBUG
1658                        std::cerr << "Hashtable changed its size\n";
1659#endif
1660                }
1661                return insert_direct( i );
1662        }
1663
1664        /*private*/
1665        bool insert_direct( item_type* i )
1666        {
1667#ifdef DEBUG
1668//              std::cerr << "sizeof(pbstorage) " << sizeof(pbstorage) << "\n";
1669#endif
1670#ifdef DEBUG
1671                std::cerr << "Inserting " << i << "\n";
1672#endif
1673                // generate hash
1674                size_type hvalue = hasher_instance(i);
1675#ifdef DEBUG
1676                std::cerr << "hvalue = " << hvalue << "\n";
1677#endif
1678                // generate slot position
1679                size_type idx = hash_slot_selector()(hvalue,this->hash_mask(table_size()));
1680#ifdef DEBUG
1681                std::cerr << "idx = " << idx << ", data is " << (void*)data  << "\n";
1682#endif
1683
1684                // get the slot at hands...
1685                // although the table_type might be some relative pointer thingie, we
1686                // use a plain pointer here since this is for internal purposes only
1687                // and any compatible pointer should have conversions to/from us
1688
1689                bool ret = inserter::insert(i,idx,&data[0]);
1690                if( ret )
1691                {
1692                        elem_size++;
1693                }
1694                // XXX check whether duplicates are allowed
1695                // do collision prevention
1696                // set slot and/or do list linking, if not already done by
1697                // collision prevention
1698                return false;
1699        }
1700
1701        void resize_slots( size_t nslots )
1702        {
1703#ifdef DEBUG
1704                std::cerr << "resize_slots(" << nslots << ")\n";
1705#endif
1706                assert( nslots >= size() );
1707                // XXX Invent some smart pointer like things to make this all exception
1708                // safe.
1709
1710                // Save a bunch of useful old values
1711                table_type odata = data;
1712                size_type olen = h_length;
1713                size_type omask = this->hash_mask(h_length);
1714#ifdef DEBUG
1715                size_type oelem = elem_size;
1716#endif
1717
1718                // now set the new wanted values
1719                h_length = nslots;
1720                data = new slot_item_type[h_length];
1721                std::fill_n( data, h_length, slot_item_type());
1722                this->reset_mask(h_length);
1723
1724                // Since for inserting we pretend to be an empty hashtable currently we
1725                // set our size to 0
1726                elem_size = 0;
1727
1728#ifdef DEBUG
1729#ifdef DEBUG
1730                std::cerr << "re-inserting " << oelem << " elements \n";
1731#endif
1732#endif
1733                for( size_t i = 0; i < olen; ++i )
1734                {
1735                        slot_item_type it = odata[i];
1736                        while(it)
1737                        {
1738#ifdef DEBUG
1739                                std::cerr << "re-inserting item chain starting at " << (void*)it << "\n";
1740#endif
1741                                // do an erase() on the old data (needs to be kept in sync with
1742                                // erase()
1743                                size_type hvalue = hasher_instance(it);
1744                                size_type idx = hash_slot_selector()(hvalue,omask);
1745                                inserter::remove(it,idx,&odata[0]);
1746
1747                                // this will insert into the new storage, not checking and/or
1748                                // triggering any resizes.
1749                                insert_direct(it);
1750                                it = odata[i];
1751                        }
1752                }
1753#ifdef DEBUG
1754                assert( oelem == elem_size );
1755#endif
1756                // data has been transferred, dispose of the slots storage
1757                delete[] odata;
1758        }
1759
1760        // XXX when we have a "never resize" or "never shrink" policy, make this
1761        // function not remove the internal storage table. Otherwise pretend that
1762        // "shrink to fit" was called.
1763        /**
1764         * @returns true if a resize of the underlying table storage has been done.
1765         */
1766        bool clear ( )
1767        {
1768#ifdef DEBUG
1769                std::cerr << "Clearing hashtable of " << size() << " elements \n";
1770#endif
1771                for( size_t i = 0; i < h_length; ++i )
1772                {
1773                        slot_item_type it = data[i];
1774                        while(it)
1775                        {
1776                                // do an erase() on the old data (needs to be kept in sync with
1777                                // erase()
1778                                size_type hvalue = hasher_instance(it);
1779                                size_type idx = hash_slot_selector()(hvalue,this->hash_mask(this->table_size()));
1780                                inserter::remove(it,idx,&data[0]);
1781                                if( this->owns_items() )
1782                                {
1783                                        delete it;
1784                                }
1785                                it = data[i];
1786                        }
1787                }
1788                return shrink_to_fit();
1789        }
1790
1791        /**
1792         * @returns true if a table resize has been done
1793         */
1794        bool shrink_to_fit( )
1795        {
1796                // XXX unimplemented
1797                return false;
1798        }
1799
1800        bool empty( ) const
1801        {
1802                return elem_size == 0;
1803        }
1804
1805        size_type max_size( ) const
1806        {
1807                return slot_resizer::max_size();
1808        }
1809        /**
1810         * @param num is the number of elements to prepare the hashtable for being
1811         * stored. If this is bigger than what the current size of the hashtable is
1812         * optimal for, then a resize will be triggered.
1813         * @returns true if the size of the hashtable was actually changed.
1814         */
1815        bool reserve( size_t num )
1816        {
1817                size_type sz = slot_resizer::optimal_size(num);
1818                if( sz > table_size() )
1819                {
1820                        resize_slots( sz );
1821                        return true;
1822                }
1823                return false;
1824        }
1825
1826    /**
1827     * Checks if the table needs to be resized according to our
1828     * resize policy and returns true if it was done, false
1829     * otherwise.
1830     */
1831        /*private*/
1832//      __attribute__((noinline))
1833        bool maybe_grow( void )
1834        {
1835                // XXX split auto resize policy into "auto grow" and "auto shrink".
1836                // Some people might never want the table to shrink automatically but
1837                // to grow. We will then also have to make the actual calculations for
1838                // grow/shrink depending on those values as they are now are done
1839                // together.
1840
1841                // check if we do auto size at all
1842                if( this->auto_size() )
1843                {
1844#ifdef DEBUG
1845                        std::cerr << "auto_resize check\n";
1846#endif
1847                        if( __builtin_expect(slot_resizer::need_grow( size(), table_size() ),0) )
1848                        {
1849#ifdef DEBUG
1850                                std::cerr << "auto resize triggered\n";
1851#endif
1852                                resize_slots( slot_resizer::optimal_size(size()) );
1853                        }
1854                }
1855                return false;
1856        }
1857
1858        bool maybe_shrink( void )
1859        {
1860                // check if we do auto size at all
1861                if( this->auto_size() )
1862                {
1863#ifdef DEBUG
1864                        std::cerr << "auto_resize check\n";
1865#endif
1866                        if( slot_resizer::need_shrink( size(), table_size() ) )
1867                        {
1868#ifdef DEBUG
1869                                std::cerr << "auto resize triggered\n";
1870#endif
1871                                resize_slots( slot_resizer::optimal_size(size()) );
1872                        }
1873                }
1874                return false;
1875        }
1876        /*
1877        iterator erase( iterator i )
1878        {
1879                iterator tmp(i);
1880                ++tmp;
1881                erase(&*i);
1882                return tmp;
1883        }
1884*/
1885
1886        bool erase( item_type* it )
1887        {
1888                // XXX Make sure that for elements caching their hash values we reset
1889                // the hash value to "unstored"
1890                size_type hvalue = hasher_instance(it);
1891                size_type idx = hash_slot_selector()(hvalue,this->hash_mask(table_size()));
1892                bool ret = inserter::remove(it,idx,&data[0]);
1893
1894                if( ret )
1895                {
1896                        maybe_shrink();
1897                }
1898
1899                return ret;
1900        }
1901
1902    /**
1903     *
1904     */
1905    item_type* find( ) { return const_cast<item_type*>(const_cast<const type*>(this)->find()); }
1906
1907    /**
1908     * Find something.
1909     * @param k is the key to search in the hashtable for. There must exist an
1910     * operator() in the hash template parameter that takes such a type, and
1911     * also this must be comparable via operator== to the item_type.
1912         * XXX Think about whether it makes sense to return an iterator instead.
1913         * Most of the cases we don't want anything besides the item, and for
1914         * iterating any position is as good as the one from find, since after all
1915         * we cannot expect to know anything about where things went.
1916     */
1917        template<class K>
1918        const item_type* find( const K& k ) const
1919        {
1920                // XXX Try to figure out if we do the exact same sequence of operations
1921                // for find/insert too, and if yes lets have a look if we can put it
1922                // into one single function, so that we only have one place to maintain
1923                // it.
1924                size_type hvalue = hasher_instance(k);
1925#ifdef DEBUG
1926                std::cerr << "Trying to find a K \"" << k << "\" with hash " << hvalue << "\n";
1927#endif
1928
1929                size_type idx = hash_slot_selector()(hvalue,this->hash_mask(table_size()));
1930#ifdef DEBUG
1931                std::cerr << "First trying at index idx = " << idx << ", data is " << (void*)data  << "\n";
1932#endif
1933
1934                slot_item_type* slot = data + idx;
1935#ifdef DEBUG
1936                std::cerr << "Chosen slot = " << (void*)slot << "\n";
1937#endif
1938                if( *slot )
1939                {
1940                        anchor_accessor aa;
1941                        item_type* next = *slot;
1942                        while( next && !compare()(*next,k) )
1943                        {
1944                                next = aa(next)->anchor.get_next();
1945                        }
1946#ifdef DEBUG
1947                        std::cerr << "Returning element at " << (void*)next << "\n";
1948#endif
1949                        return next;
1950                }
1951                else
1952                {
1953#ifdef DEBUG
1954                        std::cerr << "Chosen slot is empty\n";
1955#endif
1956                        return 0;
1957                }
1958        }
1959
1960
1961    /**
1962     * Returns the amount of occupied elements.
1963     */
1964        size_type size() const { return elem_size; }
1965
1966        size_type table_size() const
1967        {
1968                return h_length;
1969        }
1970};
1971
1972// below come some convenience wrapper templates that behave more or less like the stdlib alternatives.
1973/*
1974   template<class T, class HT<T> = hash_table >
1975hash_set
1976{
1977public:
1978    typedef size_t size_type;
1979    typedef T item_type;
1980    typedef typename HT::accesor_type accessor_type;
1981private:
1982protected:
1983public:
1984    bool insert( item_type& );
1985    bool insert( item_type* );
1986    bool erase( item_type& );
1987    bool erase( item_type* );
1988    iterator find( item_type* );
1989    iterator find( item_type& );
1990    iterator find( key_type& );
1991    iterator find( size_type );
1992    void reserve( size_type );
1993    size_type capacity( void ) const;
1994    bool resize( size_type );
1995
1996    const_iterator begin( void ) const;
1997    iterator begin( void );
1998    const_iterator end( void ) const;
1999    iterator end( void );
2000
2001};
2002
2003template<class T, class HT<...> = hash_table >
2004hash_map
2005{
2006};
2007*/
2008} // namespace iwear
2009
2010
2011/*
2012 * Future improvements
2013 * - make the load ratios optionally configurable at runtime.
2014 */
2015// vim: tabstop=4 shiftwidth=4 noexpandtab
Note: See TracBrowser for help on using the browser.