1 /*******************************************************************************
2 
3     Template for a class implementing a mapping from a user-specified type to a
4     user-specified type.
5 
6     The interface of the class has been kept deliberately simple, purely
7     handling the management of the mapping. The handling of the mapping values
8     is left entirely up to the user -- all methods simply return a pointer to
9     the mapping value which the user can do what they like with. (This is an
10     intentional design decision, in order to reduce the complexity of the
11     template.)
12 
13     The HashMap is designed as a replacement for ocean.core.ArrayMap. It has
14     several advantages:
15         1. Memory safety. As the ArrayMap's buckets are implemented as dynamic
16            arrays, each bucket will theoretically grow continually in size over
17            extended periods of use. Even when clear()ed, the buffers allocated
18            for the buckets will not reduce in size. The HashMap, on the other
19            hand, uses a pool of elements, meaning that the memory allocated for
20            each bucket is truly variable.
21         2. Code simplicity via removing optional advanced features such as
22            thread safety and value array copying.
23         3. Extensibility. Functionality is split into several modules, including
24            a base class for easier reuse of components.
25 
26     Usage example with various types stored in mapping:
27 
28     ---
29 
30         import ocean.util.container.map.HashMap;
31 
32         // Mapping from hash_t -> int
33         auto map = new HashMap!(int);
34 
35         hash_t hash = 232323;
36 
37         // Add a mapping
38         *(map.put(hash)) = 12;
39 
40         // Check if a mapping exists (null if not found)
41         auto exists = hash in map;
42 
43         // Remove a mapping
44         map.remove(hash);
45 
46         // Clear the map
47         map.clear();
48 
49         // Mapping from hash_t -> char[]
50         auto map2 = new HashMap!(char[]);
51 
52         // Add a mapping
53         map2.put(hash).copy("hello");
54 
55         // Mapping from hash_t -> struct
56         struct MyStruct
57         {
58             int x;
59             float y;
60         }
61 
62         auto map3 = new HashMap!(MyStruct);
63 
64         // Add a mapping
65         *(map3.put(hash)) = MyStruct(12, 23.23);
66 
67     ---
68 
69     Copyright:
70         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
71         All rights reserved.
72 
73     License:
74         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
75         Alternatively, this file may be distributed under the terms of the Tango
76         3-Clause BSD License (see LICENSE_BSD.txt for details).
77 
78 *******************************************************************************/
79 
80 module ocean.util.container.map.Map;
81 
82 
83 
84 
85 import ocean.meta.types.Qualifiers;
86 
87 import ocean.util.container.map.model.BucketSet;
88 
89 import ocean.util.container.map.model.Bucket;
90 
91 import ocean.util.container.map.model.MapIterator;
92 
93 import ocean.util.container.map.model.StandardHash;
94 
95 version (UnitTestVerbose) import ocean.io.Stdout;
96 
97 
98 
99 /*******************************************************************************
100 
101     Debug switch for verbose unittest output (uncomment if desired)
102 
103 *******************************************************************************/
104 
105 //version = UnitTestVerbose;
106 
107 version ( UnitTestVerbose )
108 {
109     import ocean.io.Stdout;
110 }
111 
112 /*******************************************************************************
113 
114     StandardKeyHashingMap class template. Manages a mapping from K to V, using
115     a standard way of hash calculation:
116 
117     - If K is a primitive type (integer, floating point, character), the hash
118       value is calculated from the raw key data using the FNV1a hash function.
119       That means, if the keys are dynamic arrays, including strings, the array
120       content is used as the key, not the array instance (ptr/length).
121     - If K is a dynamic or static array of a  primitive type, the hash value is
122       calculated from the raw data of the key array content using the FNV1a hash
123       function.
124     - If K is a class, struct or union, it is expected to implement toHash(),
125       which will be used.
126     - Other key types (arrays of non-primitive types, classes/structs/unions
127       which do not implement toHash(), pointers, function references, delegates,
128       associative arrays) are not supported by this class template.
129 
130     Params:
131         V = type to store in values of map
132         K = type to store in keys of map
133 
134 *******************************************************************************/
135 
136 public class StandardKeyHashingMap ( V, K ) : Map!(V, K)
137 {
138     /***************************************************************************
139 
140         Constructor.
141 
142         Params:
143             n = expected number of elements in mapping
144             load_factor = ratio of n to the number of internal buckets. The
145                 desired (approximate) number of elements per bucket. For
146                 example, 0.5 sets the number of buckets to double n; for 2 the
147                 number of buckets is the half of n. load_factor must be greater
148                 than 0. The load factor is basically a trade-off between memory
149                 usage (number of buckets) and search time (number of elements
150                 per bucket).
151 
152     ***************************************************************************/
153 
154     public this ( size_t n, float load_factor = 0.75 )
155     {
156         super(n, load_factor);
157     }
158 
159     /***************************************************************************
160 
161         Constructor.
162 
163         Params:
164             allocator = custom bucket elements allocator
165             n = expected number of elements in mapping
166             load_factor = ratio of n to the number of internal buckets. The
167                 desired (approximate) number of elements per bucket. For
168                 example, 0.5 sets the number of buckets to double n; for 2 the
169                 number of buckets is the half of n. load_factor must be greater
170                 than 0. The load factor is basically a trade-off between memory
171                 usage (number of buckets) and search time (number of elements
172                 per bucket).
173 
174     ***************************************************************************/
175 
176     public this ( IAllocator allocator, size_t n, float load_factor = 0.75 )
177     {
178         super(allocator, n, load_factor);
179     }
180 
181 
182     /***************************************************************************
183 
184         Mixin of the toHash() method which is declared abstract in BucketSet.
185 
186     ***************************************************************************/
187 
188     override:
189         mixin StandardHash.toHash!(K);
190 }
191 
192 /*******************************************************************************
193 
194     StandardKeyHashingMap class template. Manages a mapping from K to ubyte[V],
195     using a standard way of hash calculation:
196 
197     - If K is a primitive type (integer, floating point, character), the hash
198       value is calculated from the raw key data using the FNV1a hash function.
199     - If K is a dynamic or static array of a primitive type, the hash value is
200       calculated from the raw data of the key array content using the FNV1a hash
201       function.
202     - If K is a class, struct or union, it is expected to implement toHash(),
203       which will be used.
204     - Other key types (arrays of non-primitive types, classes/structs/unions
205       which do not implement toHash(), pointers, function references, delegates,
206       associative arrays) are not supported by this class template.
207 
208     Params:
209         V = byte length of the values to store in the map, must be at least 1
210         K = type to store in keys of map
211 
212 *******************************************************************************/
213 
214 public class StandardKeyHashingMap ( size_t V, K ) : Map!(V, K)
215 {
216     /***************************************************************************
217 
218         Constructor.
219 
220         Params:
221             n = expected number of elements in mapping
222             load_factor = ratio of n to the number of internal buckets. The
223                 desired (approximate) number of elements per bucket. For
224                 example, 0.5 sets the number of buckets to double n; for 2 the
225                 number of buckets is the half of n. load_factor must be greater
226                 than 0. The load factor is basically a trade-off between memory
227                 usage (number of buckets) and search time (number of elements
228                 per bucket).
229 
230     ***************************************************************************/
231 
232     public this ( size_t n, float load_factor = 0.75 )
233     {
234         super(n, load_factor);
235     }
236 
237     /***************************************************************************
238 
239         Constructor.
240 
241         Params:
242             allocator = custom bucket elements allocator
243             n = expected number of elements in mapping
244             load_factor = ratio of n to the number of internal buckets. The
245                 desired (approximate) number of elements per bucket. For
246                 example, 0.5 sets the number of buckets to double n; for 2 the
247                 number of buckets is the half of n. load_factor must be greater
248                 than 0. The load factor is basically a trade-off between memory
249                 usage (number of buckets) and search time (number of elements
250                 per bucket).
251 
252     ***************************************************************************/
253 
254     public this ( IAllocator allocator, size_t n, float load_factor = 0.75 )
255     {
256         super(allocator, n, load_factor);
257     }
258 
259     /***************************************************************************
260 
261         Mixin of the toHash() method which is declared abstract in BucketSet.
262 
263     ***************************************************************************/
264 
265     override:
266         mixin StandardHash.toHash!(K);
267 }
268 
269 /*******************************************************************************
270 
271     Map class template to store values of a certain type. Manages a mapping
272     from K to V, leaving the hash function implementation to the subclass
273     (abstract BucketSet.toHash()).
274 
275     Params:
276         V = type to store in values of map
277         K = type to store in keys of map
278 
279 *******************************************************************************/
280 
281 public abstract class Map ( V, K ) : BucketSet!(V.sizeof, K)
282 {
283     // add to overload set explicitly
284     alias BucketSet!(V.sizeof, K).remove remove;
285 
286     /***************************************************************************
287 
288         MapIterator template instance.
289 
290     ***************************************************************************/
291 
292     alias .MapIterator!(V, K) MapIterator;
293 
294     /***************************************************************************
295 
296         If V is a static array, opIndex() und opIndexAssign() need to return a
297         dynamic array slicing the value.
298 
299         V.init redefinition to work around DMD bug 7752: If V is a static array,
300         then V.init is of the array base type.
301 
302     ***************************************************************************/
303 
304     static if (is (V Base : Base[]) && !is (V == Base[]))
305     {
306         static if (is (typeof (V.init) == V))
307         {
308             pragma (msg, "DMD bug 7752 is fixed, please remove the workaround ",
309                          "in ", __FILE__, ":", __LINE__.stringof);
310         }
311 
312         static immutable V_is_static_array = true;
313 
314         alias Base[] VReturn;
315 
316         static immutable Base[V.length] v_init = Base.init;
317     }
318     else
319     {
320         static immutable V_is_static_array = false;
321 
322         alias V VReturn;
323 
324         static immutable v_init = V.init;
325     }
326 
327     /***************************************************************************
328 
329         Mixin of the specialized iterator classes which inherit from
330         BucketSet.Iterator.
331         This makes available three iterator classes that can be newed to allow
332         certain iteration behaviors:
333 
334         * Iterator — just a normal iterator
335         * InterruptibleIterator — an iterator that can be interrupted and
336           resumed, but that has to be manually reset with reset() if the
337           iteration is meant to be repeated
338 
339         If the map is modified between interrupted iterations, it can happen
340         that new elements that were added in the mean time won't appear in the
341         iteratation, depending on whether they end up in a bucket that was
342         already iterated or not.
343 
344         Iterator usage example
345         ---
346         auto map = new HashMap!(size_t);
347 
348         auto it = map.new Iterator();
349 
350         // A normal iteration over the map
351         foreach ( k, v; it )
352         {
353             ..
354         }
355 
356         // Equal to
357         foreach ( k, v; map )
358         {
359             ..
360         }
361         ---
362 
363         InterruptibleIterator
364         ---
365         auto map = new HashMap!(size_t);
366 
367         auto interruptible_it = map.new InterruptibleIterator();
368 
369         // Iterate over the first 100k elements
370         foreach ( i, k, v; interruptible_it )
371         {
372             ..
373             // Break after 100k elements
374             if ( i % 100_000 == 0 ) break;
375         }
376 
377         // Iterate over the next 100k elments
378         foreach ( i, k, v; interruptible_it )
379         {
380             ..
381             // Break after 100k elements
382             if ( i % 100_000 == 0 ) break;
383         }
384 
385         // Assuming the map had 150k elements, the iteration is done now,
386         // so this won't do anything
387         foreach ( i, k, v; interruptible_it )
388         {
389             ..
390             // Break after 100k elements
391             if ( i % 100_000 == 0 ) break;
392         }
393 
394         assert ( interruptible_it.finished() == true );
395         ---
396 
397         See also: BucketSet.Iterator, MapIterator.IteratorClass
398 
399     ***************************************************************************/
400 
401     mixin IteratorClass!(BucketSet!(V.sizeof, K).Iterator, MapIterator);
402 
403     /***************************************************************************
404 
405         Constructor.
406 
407         Params:
408             n = expected number of elements in mapping
409             load_factor = ratio of n to the number of internal buckets. The
410                 desired (approximate) number of elements per bucket. For
411                 example, 0.5 sets the number of buckets to double n; for 2 the
412                 number of buckets is the half of n. load_factor must be greater
413                 than 0. The load factor is basically a trade-off between memory
414                 usage (number of buckets) and search time (number of elements
415                 per bucket).
416 
417     ***************************************************************************/
418 
419     protected this ( size_t n, float load_factor = 0.75 )
420     {
421         super(n, load_factor);
422     }
423 
424     /***************************************************************************
425 
426         Constructor.
427 
428         Params:
429             allocator = custom bucket elements allocator
430             n = expected number of elements in mapping
431             load_factor = ratio of n to the number of internal buckets. The
432                 desired (approximate) number of elements per bucket. For
433                 example, 0.5 sets the number of buckets to double n; for 2 the
434                 number of buckets is the half of n. load_factor must be greater
435                 than 0. The load factor is basically a trade-off between memory
436                 usage (number of buckets) and search time (number of elements
437                 per bucket).
438 
439     ***************************************************************************/
440 
441     protected this ( IAllocator allocator, size_t n, float load_factor = 0.75 )
442     {
443         super(allocator, n, load_factor);
444     }
445 
446     /***************************************************************************
447 
448         In operator. Looks up the value mapped by key.
449 
450         Note: If it is sure that a value for key is in the map, in other words,
451         it would be a bug if it isn't, get() below is the preferred method to
452         use because it guarantees never to return a null pointer.
453 
454         Params:
455             key = key to look up the value for
456 
457         Returns:
458             pointer to the value mapped by key, if it exists. null otherwise.
459 
460     ***************************************************************************/
461 
462     public V* opBinaryRight (string op : "in") ( in K key )
463     {
464         auto element = this.get_(key);
465 
466         return element? cast(V*)element.val[0 .. V.sizeof].ptr : null;
467     }
468 
469     /***************************************************************************
470 
471         Obtains a reference to the value mapped by key. A value for key is
472         expected to exist in the map.
473 
474         Note: Use this method if it is sure that a value for key is in the map,
475         in other words, it would be a bug if it isn't. To look up a mapping that
476         may or may not exist, use the 'in' operator (opBinaryRight!"in" above).
477 
478         Params:
479             key = key to obtain the value for
480 
481         Returns:
482             pointer to the value mapped by key.
483 
484         Out:
485             The returned pointer is never null, key must be in the map.
486 
487     ***************************************************************************/
488 
489     public V* get ( in K key )
490     out (val)
491     {
492         assert (val !is null);
493     }
494     do
495     {
496         return cast(V*)this.get_(key, true).val[0 .. V.sizeof].ptr;
497     }
498 
499     /***************************************************************************
500 
501         Obtains a the value mapped by key. A value for key is expected to exist
502         in the map.
503 
504         Note: Use this method if it is sure that a value for key is in the map,
505         in other words, it would be a bug if it isn't. To look up a mapping that
506         may or may not exist, use the 'in' operator (opBinaryRight!"in" above).
507 
508         Params:
509             key = key to obtain the value for
510 
511         Returns:
512             the value mapped by key.
513 
514     ***************************************************************************/
515 
516     public VReturn opIndex ( in K key )
517     {
518         return *this.get(key);
519     }
520 
521     /***************************************************************************
522 
523         Looks up the mapping for key or adds one if not found.
524 
525         Note that, if a new mapping was added (added outputs true), the returned
526         pointer may reference a previously removed value. If this is not
527         desired, set the value referenced to by the pointer returned by remove()
528         to the desired initial value (e.g. V.init).
529 
530         Params:
531             key   = key to look up or add mapping for
532             added = set to true if the mapping did not exist but was added
533 
534         Returns:
535             the value mapped to by the specified key. If added outputs true, the
536             value is unspecified and the caller should set the value as desired.
537 
538         Out:
539             The returned pointer is never null.
540 
541     ***************************************************************************/
542 
543     public V* put ( K key, out bool added )
544     out (val)
545     {
546         assert (val !is null);
547     }
548     do
549     {
550         return cast(V*)this.put_(key, added).val[0 .. V.sizeof].ptr;
551     }
552 
553     /***************************************************************************
554 
555         Adds or updates a mapping from the specified key.
556 
557         Note that the returned slice may reference a previously removed value.
558         If this is not desired, set the value referenced to by the pointer
559         returned by remove() to the desired initial value (e.g. V.init).
560 
561         Params:
562             key = key to add/update mapping for
563 
564         Returns:
565             pointer to the value mapped to by the specified key. The caller
566             should set the value as desired.
567 
568         Out:
569             The returned pointer is never null.
570 
571     ***************************************************************************/
572 
573     public V* put ( K key )
574     out (val)
575     {
576         assert (val !is null);
577     }
578     do
579     {
580         return cast(V*)this.put_(key).val[0 .. V.sizeof].ptr;
581     }
582 
583     /***************************************************************************
584 
585         Adds or updates a mapping from the specified key.
586 
587         Params:
588             key = key to add/update mapping for
589             val = value to map to
590 
591         Returns:
592             val
593 
594     ***************************************************************************/
595 
596     public VReturn opIndexAssign ( V val, K key )
597     {
598         static if (V_is_static_array)
599         {
600             return (*this.put(key))[] = val[];
601         }
602         else
603         {
604             return *this.put(key) = val;
605         }
606     }
607 
608     /***************************************************************************
609 
610         Removes the mapping for the specified key and optionally invokes dg with
611         the value that is about to be removed.
612 
613         Note that, if references to GC-allocated objects (objects or dynamic
614         arrays), it is a good idea to set the value referenced to by the
615         returned pointer to null to avoid these objects from being prevented
616         from garbage collection. In general pointers should be set to null for
617         the same reason and to avoid dangling pointers.
618 
619         If the default allocator is used (that is, no allocator instance was
620         passed to the constructor), the value referenced by the val parameter of
621         dg is accessible and remains unchanged after dg returned until the next
622         call to put() or clear().
623 
624         Params:
625             key = key to remove mapping for
626             dg  = optional delegate to call with the removed value (not called
627                   if key was not found)
628 
629         Returns:
630             true if key was found in the map or false if not. In case of false
631             dg was not called.
632 
633     ***************************************************************************/
634 
635     public bool remove ( K key, scope void delegate ( ref V val ) dg = null )
636     {
637         scope dg2 = (ref Bucket.Element element)
638                     {
639                         dg(*cast(V*)element.val[0 .. V.sizeof].ptr);
640                     };
641 
642         // Issue 16037
643         return this.remove_(key, dg ? dg2 : null);
644     }
645 
646     /***************************************************************************
647 
648         'foreach' iteration over key/value pairs currently in the map.
649 
650         Note: If V or K (or both) are a static array, the corresponding
651         iteration variable is a dynamic array of the same base type and slices
652         the key or value.
653         (The reason is that static array 'ref' parameters are forbidden in D.)
654 
655         Note: It is possible to have interruptible iterations, see documentation
656         for mixin of IteratorClass
657 
658         See also: BucketSet.Iterator, MapIterator.IteratorClass
659 
660     ***************************************************************************/
661 
662     public int opApply ( MapIterator.Dg dg )
663     {
664         scope it = this.new Iterator;
665 
666         return it.opApply(dg);
667     }
668 
669     /***************************************************************************
670 
671         Same as above, but includes a counter
672 
673     ***************************************************************************/
674 
675     public int opApply ( MapIterator.Dgi dgi )
676     {
677         scope it = this.new Iterator;
678 
679         return it.opApply(dgi);
680     }
681 
682     /***************************************************************************
683 
684         Removes all elements from all buckets and sets the element values to
685         val_init.
686 
687         Note:
688             Beware that calling this.clear() is known to sometimes cause
689             unexpected behaviour when the map is reused afterwards (where cyclic
690             links are introduced in the bucket-set).
691             Call this method instead as it has been reported to properly clear
692             the map.
693 
694         Params:
695             val_init = initialisation value
696 
697         Returns:
698             this instance
699 
700     ***************************************************************************/
701 
702     public typeof(this) clearErase ( in V val_init = v_init )
703     {
704         this.clear_((cast (void*) &val_init)[0 .. val_init.sizeof]);
705 
706         return this;
707     }
708 }
709 
710 /*******************************************************************************
711 
712     HashMap class template to store the raw data of values of a certain size.
713     Manages a mapping from K to ubyte[V], leaving the hash function implementation
714     to the subclass (abstract BucketSet.toHash()).
715     Since static arrays cannot be returned, the access methods return a void[]
716     slice to the value.
717 
718     Params:
719         V = byte length of the values to store in the map, must be at least 1
720         K = type to store in keys of map
721 
722 *******************************************************************************/
723 
724 public abstract class Map ( size_t V, K ) : BucketSet!(V, K)
725 {
726     import ocean.core.Verify;
727 
728     /***************************************************************************
729 
730         V check.
731 
732     ***************************************************************************/
733 
734     static assert (V, "Please use Set for zero-length values.");
735 
736     /***************************************************************************
737 
738         MapIterator template instance.
739 
740     ***************************************************************************/
741 
742     alias .MapIterator!(Bucket.Element.Val, K) MapIterator;
743 
744     /***************************************************************************
745 
746         Mixin of the specialized iterator classes which inherit from
747         BucketSet.Iterator.
748 
749         This makes available three iterator classes that can be newed to allow
750         certain iteration behaviors:
751 
752         * Iterator — just a normal iterator
753         * InterruptibleIterator — an iterator that can be interrupted and
754           resumed, but that has to be manually reset with reset() if the
755           iteration is meant to be repeated
756 
757         If the map is modified between interrupted iterations, it can happen
758         that new elements that were added in the mean time won't appear in the
759         iteratation, depending on whether they end up in a bucket that was
760         already iterated or not.
761 
762         Iterator usage example
763         ---
764         auto map = new HashMap!(size_t);
765 
766         auto it = map.new Iterator();
767 
768         // A normal iteration over the map
769         foreach ( k, v; it )
770         {
771             ..
772         }
773 
774         // Equal to
775         foreach ( k, v; map )
776         {
777             ..
778         }
779         ---
780 
781         InterruptibleIterator
782         ---
783         auto map = new HashMap!(size_t);
784 
785         auto interruptible_it = map.new InterruptibleIterator();
786 
787         // Iterate over the first 100k elements
788         foreach ( i, k, v; interruptible_it )
789         {
790             ..
791             // Break after 100k elements
792             if ( i % 100_000 == 0 ) break;
793         }
794 
795         // Iterate over the next 100k elments
796         foreach ( i, k, v; interruptible_it )
797         {
798             ..
799             // Break after 100k elements
800             if ( i % 100_000 == 0 ) break;
801         }
802 
803         // Assuming the map had 150k elements, the iteration is done now,
804         // so this won't do anything
805         foreach ( i, k, v; interruptible_it )
806         {
807             ..
808             // Break after 100k elements
809             if ( i % 100_000 == 0 ) break;
810         }
811 
812         assert ( interruptible_it.finished() == true );
813         ---
814 
815         See also: BucketSet.Iterator, MapIterator.IteratorClass
816 
817     ***************************************************************************/
818 
819     mixin IteratorClass!(BucketSet!(V,K).Iterator, MapIterator);
820 
821     /***************************************************************************
822 
823         Constructor.
824 
825         Params:
826             n = expected number of elements in mapping
827             load_factor = ratio of n to the number of internal buckets. The
828                 desired (approximate) number of elements per bucket. For
829                 example, 0.5 sets the number of buckets to double n; for 2 the
830                 number of buckets is the half of n. load_factor must be greater
831                 than 0. The load factor is basically a trade-off between memory
832                 usage (number of buckets) and search time (number of elements
833                 per bucket).
834 
835     ***************************************************************************/
836 
837     protected this ( size_t n, float load_factor = 0.75 )
838     {
839         super(n, load_factor);
840     }
841 
842     /***************************************************************************
843 
844         In operator. Looks up the value mapped by key.
845 
846         Note: If it is sure that a value for key is in the map, in other words,
847         it would be a bug if it isn't, get() below is the preferred method to
848         use because it guarantees never to return a null pointer.
849 
850         Params:
851             key = key to look up the value for
852 
853         Returns:
854             an array slicing the value buffer mapped by key, if it exists, or
855             null otherwise.
856 
857         Out:
858             The returned array is either null or has the length V.
859 
860      ***************************************************************************/
861 
862     public void[] opBinaryRight (string op : "in") ( in K key )
863     out (val)
864     {
865         if (val)
866         {
867             assert (val.length == V);
868         }
869     }
870     do
871     {
872         return this.get_(key).val;
873     }
874 
875     /***************************************************************************
876 
877         Obtains a reference to the value mapped by key. A value for key is
878         expected to exist in the map.
879 
880         Note: Use this method if it is sure that a value for key is in the map,
881         in other words, it would be a bug if it isn't. To look up a mapping that
882         may or may not exist, use the 'in' operator (opBinaryRight!"in"above).
883 
884         Params:
885             key = key to obtain the value for
886 
887         Returns:
888             pointer to the value mapped by key.
889 
890         Out:
891             The returned array is never null and has the length V.
892 
893     ***************************************************************************/
894 
895     public void[] get ( in K key )
896     out (val)
897     {
898         assert (val.length == V);
899     }
900     do
901     {
902         return this.get_(key, true).val;
903     }
904 
905     /***************************************************************************
906 
907         Obtains a the value mapped by key. A value for key is expected to exist
908         in the map.
909 
910         Note: Use this method if it is sure that a value for key is in the map,
911         in other words, it would be a bug if it isn't. To look up a mapping that
912         may or may not exist, use the 'in' operator (opBinaryRight"in" above).
913 
914         Params:
915             key = key to obtain the value for
916 
917         Returns:
918             the value mapped by key.
919 
920     ***************************************************************************/
921 
922     alias get opIndex;
923 
924     /***************************************************************************
925 
926         Looks up the mapping for key or adds one if not found.
927 
928         Note that, if a new mapping was added (added outputs true), the returned
929         slice may reference a previously removed value. If this is not desired,
930         copy the desired initial value into the sliced buffer returned by
931         remove().
932 
933         Params:
934             key   = key to add/update mapping for
935             added = set to true if the record did not exist but was added
936 
937         Returns:
938             an array slicing the value buffer mapped to by the specified key. If
939             added outputs true, the value is unspecified and the caller should
940             set the value as desired.
941 
942         Out:
943             The returned array is never null and has the length V.
944 
945      ***************************************************************************/
946 
947     public void[] put ( in K key, out bool added )
948     out (val)
949     {
950         assert (val.length == V);
951     }
952     do
953     {
954         return this.put_(key, added).val;
955     }
956 
957     /***************************************************************************
958 
959         Adds or updates a mapping from the specified key. Note that, if a new
960         mapping was added (added outputs true), the returned slice may reference
961         a previously removed value. If this is not desired, copy the desired
962         initial value into the sliced buffer returned by remove().
963 
964         Params:
965             key   = key to add/update mapping for
966 
967         Returns:
968             an array slicing the value buffer mapped to by the specified key.
969             The caller should set the value as desired.
970 
971         Out:
972             The returned array is never null and has the length V.
973 
974      **************************************************************************/
975 
976     public void[] put ( K key )
977     out (val)
978     {
979         assert (val.length == V);
980     }
981     do
982     {
983         bool added;
984 
985         return this.put_(key, added).val;
986     }
987 
988     /***************************************************************************
989 
990         Adds or updates a mapping from key to val, copying the content of val
991         into the map.
992 
993         Params:
994             key = key to add/update mapping for
995             val = value to map to
996 
997         Returns:
998             val
999 
1000         In:
1001             val.length must be V.
1002 
1003     ***************************************************************************/
1004 
1005     public void[] opIndexAssign ( void[] val, K key )
1006     {
1007         verify (val.length == V, "expected a value of length " ~ V.stringof);
1008 
1009         bool added;
1010 
1011         this.put_(key, added).val[] = val[];
1012 
1013         return val;
1014     }
1015 
1016     /***************************************************************************
1017 
1018         Removes the mapping for the specified key.
1019 
1020         Params:
1021             key = key to remove mapping for
1022 
1023         Returns:
1024             an array slicing the value buffer of the removed element, if found,
1025             or null otherwise. It is guaranteed that the referenced value will
1026             remain unchanged until the next call to put(), which may reuse it,
1027             or to clear().
1028 
1029         Out:
1030             The returned array is either null or has the length V.
1031 
1032     ***************************************************************************/
1033 
1034     public void[] remove ( in K key )
1035     out (val)
1036     {
1037         if (val)
1038         {
1039             assert (val.length == V);
1040         }
1041     }
1042     do
1043     {
1044         return this.remove_(key).val;
1045     }
1046 
1047     /***************************************************************************
1048 
1049         'foreach' iteration over key/value pairs currently in the map.
1050 
1051         Note: It is possible to have interruptible iterations, see documentation
1052         for mixin of IteratorClass
1053 
1054         See also: BucketSet.Iterator, MapIterator.IteratorClass
1055 
1056         Notes:
1057         - During iteration it is forbidden to call clear() or redistribute() or
1058           remove map elements. If elements are added, the iteration may or may
1059           not include these elements.
1060         - If V or K (or both) are a static array, the corresponding iteration
1061           variable is a dynamic array of the same base type and slices the key
1062           or value of the element in the map. (The reason is that static array
1063           'ref' parameters are forbidden in D.)
1064           In this case it is not recommended to do a 'ref' iteration over key or
1065           value. To modify a value during iteration, copy the new value contents
1066           into the array content. Example:
1067           ---
1068               // Using the StandardKeyHashingMap subclass because Map is an
1069               // abstract class (inherits abstract toHash()).
1070 
1071               alias int[7]  ValueType;
1072               alias char[4] KeyType;
1073 
1074               auto map = new StandardKeyHashingMap!(ValueType, KeyType);
1075 
1076               // Side note: Use the '[x, y, ...]' array literal only with
1077               // constants or in code locations that are not executed repeatedly
1078               // because for variables it invokes a buffer allocation, leading
1079               // to a memory leak condition when it is done very often.
1080 
1081               const int[7] new_value = [2, 3, 5, 7, 11, 13, 17];
1082 
1083               foreach (key, val; map)
1084               {
1085                   // - key is of type char[] and slices the key of the current
1086                   //   map element so key.length is guaranteed to be 4,
1087                   // - val is of type int[] and slices the value of the current
1088                   //   map element so val.length is guaranteed to be 7.
1089 
1090                   // Modify the value by copying into the static array
1091                   // referenced by val.
1092 
1093                   val[] = new_value[];
1094 
1095                   // It is also possible to modify single val array elements.
1096 
1097                   val[2] += val[5] * 4711;
1098               }
1099           ---
1100           DO NOT do that with the key or modify it in-place in any way!
1101 
1102         - It is not recommended to specify 'ref' for the key iteration variable.
1103           If you do it anyway, DO NOT modify the key in-place!
1104 
1105     ***************************************************************************/
1106 
1107     public int opApply ( MapIterator.Dg dg )
1108     {
1109         scope it = this.new Iterator;
1110 
1111         return it.opApply(dg);
1112     }
1113 
1114     /***************************************************************************
1115 
1116         Same method as above, but includes a counter
1117 
1118     ***************************************************************************/
1119 
1120     public int opApply ( MapIterator.Dgi dgi )
1121     {
1122         scope it = this.new Iterator;
1123 
1124         return it.opApply(dgi);
1125     }
1126 
1127     /***************************************************************************
1128 
1129         Removes all elements from all buckets and sets the element values to
1130         val_init.
1131 
1132         Params:
1133             val_init = initialisation value
1134 
1135         Returns:
1136             this instance
1137 
1138      **************************************************************************/
1139 
1140     public typeof(this) clear ( void[] val_init = null )
1141     {
1142         verify (!val_init.length || val_init.length == V,
1143                 "val_init.length expected to be 0 or " ~ V);
1144 
1145         this.clear_(val_init);
1146 
1147         return this;
1148     }
1149 }
1150 
1151 /******************************************************************************
1152 
1153     Test key types smaller than size_t (or even equals) don't screw up the
1154     alignment and makes impossible to the GC to scan pointers in the value.
1155 
1156 ******************************************************************************/
1157 
1158 version (unittest)
1159 {
1160     import core.memory;
1161     import ocean.core.Test;
1162 
1163     void test_key (T) ()
1164     {
1165         auto map = new StandardKeyHashingMap!(mstring, T)(10);
1166 
1167         for (T i = 0; i < 10; i++)
1168         {
1169             auto p = map.put(i);
1170             *p = "Sociomantic".dup;
1171         }
1172 
1173         GC.collect();
1174 
1175         for (T i = 0; i < 10; i++)
1176         {
1177             auto p = map.get(i);
1178             test!("==")(*p, "Sociomantic"[]);
1179         }
1180     }
1181 
1182     void test_val (T) ()
1183     {
1184         auto map = new StandardKeyHashingMap!(T, mstring)(10);
1185 
1186         for (T i = 0; i < 10; i++)
1187         {
1188             auto p = map.put("Sociomantic".dup ~ cast(char) (0x30+i));
1189             *p = i;
1190         }
1191 
1192         GC.collect();
1193 
1194         for (T i = 0; i < 10; i++)
1195         {
1196             auto p = map.get("Sociomantic".dup ~ cast(char) (0x30+i));
1197             test!("==")(*p, i);
1198         }
1199     }
1200 
1201     import MallocAllocator = ocean.util.container.map.model.BucketElementMallocAllocator;
1202     import GCAllocator = ocean.util.container.map.model.BucketElementGCAllocator;
1203     import FreeListAllocator = ocean.util.container.map.model.BucketElementFreeList;
1204 }
1205 
1206 unittest
1207 {
1208     test_key!(byte);
1209     test_key!(short);
1210     test_key!(int);
1211     test_key!(long);
1212 
1213     test_val!(byte);
1214     test_val!(short);
1215     test_val!(int);
1216     test_val!(long);
1217 }
1218 
1219 unittest
1220 {
1221     // ensure opIn works with const keys
1222     auto map = new StandardKeyHashingMap!(int, mstring)(5);
1223     auto v = "something" in map;
1224     test!("is")(v, null);
1225 }
1226 
1227 unittest
1228 {
1229     // ensure class keys work
1230     class Key
1231     {
1232         int x;
1233 
1234         this ( int x )
1235         {
1236             this.x = x;
1237         }
1238 
1239         override hash_t toHash ( )
1240         {
1241             return x;
1242         }
1243     }
1244 
1245     auto map = new StandardKeyHashingMap!(int, Key)(5);
1246     auto key = new Key(42);
1247     map[key] = 24;
1248     auto v = key in map;
1249     test!("!is")(v, null);
1250     test!("==")(*v, 24);
1251 }
1252 
1253 /*******************************************************************************
1254 
1255     Instantiate the bucket element allocator templates.
1256 
1257 *******************************************************************************/
1258 
1259 unittest
1260 {
1261     MallocAllocator.instantiateAllocator!(StandardKeyHashingMap!(int, int));
1262     GCAllocator.instantiateAllocator!(StandardKeyHashingMap!(int, int));
1263     FreeListAllocator.instantiateAllocator!(StandardKeyHashingMap!(int, int));
1264 }