Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Ticket #177: WorkingParseTest.d

File WorkingParseTest.d, 20.9 kB (added by debio, 15 years ago)

See next comment.

Line 
1 module ParseTest;
2
3 int main(char[][] args) {
4     HashSet!(int) bob = new HashSet!(int)();
5     return 0;
6 }
7
8
9 private import  tango.util.container.Slink;
10
11 /*******************************************************************************
12
13 copyright:      Copyright (c) 2008 Kris Bell. All rights reserved
14
15 license:        BSD style: $(LICENSE)
16
17 version:        Apr 2008: Initial release
18                 Jan 2009: Added GCChunk allocator
19
20 authors:        Kris, schveiguy
21
22 Since:          0.99.7
23
24 *******************************************************************************/
25
26 private import tango.core.Memory;
27
28 private import tango.stdc.stdlib;
29 private import tango.stdc.string;
30
31 /*******************************************************************************
32
33 Utility functions and constants
34
35 *******************************************************************************/
36
37 struct Container
38 {
39 /***********************************************************************
40
41        default initial number of buckets of a non-empty hashmap
42
43 ***********************************************************************/
44
45 static int defaultInitialBuckets = 31;
46
47 /***********************************************************************
48
49         default load factor for a non-empty hashmap. The hash
50         table is resized when the proportion of elements per
51         buckets exceeds this limit
52
53 ***********************************************************************/
54
55 static float defaultLoadFactor = 0.75f;
56
57 /***********************************************************************
58
59         generic value reaper, which does nothing
60
61 ***********************************************************************/
62
63 static void reap(V) (V v) {}
64
65 /***********************************************************************
66
67         generic key/value reaper, which does nothing
68
69 ***********************************************************************/
70
71 static void reap(K, V) (K k, V v) {}
72
73 /***********************************************************************
74
75         generic hash function, using the default hashing. Thanks
76         to 'mwarning' for the optimization suggestion
77
78 ***********************************************************************/
79
80 static uint hash(K) (K k, uint length)
81 {
82         static if (is(K : int) || is(K : uint) ||
83                    is(K : long) || is(K : ulong) ||
84                    is(K : short) || is(K : ushort) ||
85                    is(K : byte) || is(K : ubyte) ||
86                    is(K : char) || is(K : wchar) || is (K : dchar))
87                    return cast(uint) (k % length);
88         else
89            return (typeid(K).getHash(&k) & 0x7FFFFFFF) % length;
90 }
91
92 /***********************************************************************
93
94         generic GC allocation manager
95         
96 ***********************************************************************/
97
98 struct Collect(T)
99 {
100         /***************************************************************
101
102                 allocate a T sized memory chunk
103                 
104         ***************************************************************/
105
106         T* allocate ()
107         {       
108                 return cast(T*) GC.calloc (T.sizeof);
109         }
110
111         /***************************************************************
112
113                 allocate an array of T sized memory chunks
114                 
115         ***************************************************************/
116
117         T*[] allocate (uint count)
118         {
119                 return new T*[count];
120         }
121
122         /***************************************************************
123
124                 Invoked when a specific T[] is discarded
125                 
126         ***************************************************************/
127
128         void collect (T* p)
129         {
130                 if (p)
131                     delete p;
132         }
133
134         /***************************************************************
135
136                 Invoked when a specific T[] is discarded
137                 
138         ***************************************************************/
139
140         void collect (T*[] t)
141         {     
142                 if (t)
143                     delete t;
144         }
145
146         /***************************************************************
147
148                 Invoked when clear/reset is called on the host.
149                 This is a shortcut to clear everything allocated.
150
151                 Should return true if supported, or false otherwise.
152                 False return will cause a series of discrete collect
153                 calls
154
155         ***************************************************************/
156
157         bool collect (bool all = true)
158         {
159                 return false;
160         }
161 }        
162
163        
164 /***********************************************************************
165
166         Malloc allocation manager.
167
168         Note that, due to GC behaviour, you should not configure
169         a custom allocator for containers holding anything managed
170         by the GC. For example, you cannot use a MallocAllocator
171         to manage a container of classes or strings where those
172         were allocated by the GC. Once something is owned by a GC
173         then it's lifetime must be managed by GC-managed entities
174         (otherwise the GC may think there are no live references
175         and prematurely collect container contents).
176
177         You can explicity manage the collection of keys and values
178         yourself by providing a reaper delegate. For example, if
179         you use a MallocAllocator to manage key/value pairs which
180         are themselves allocated via malloc, then you should also
181         provide a reaper delegate to collect those as required.     
182         
183 ***********************************************************************/
184
185 struct Malloc(T)
186 {
187         /***************************************************************
188
189                 allocate an array of T sized memory chunks
190                 
191         ***************************************************************/
192
193         T* allocate ()
194         {
195                 return cast(T*) calloc (1, T.sizeof);
196         }
197
198         /***************************************************************
199
200                 allocate an array of T sized memory chunks
201                 
202         ***************************************************************/
203
204         T*[] allocate (uint count)
205         {
206                 return (cast(T**) calloc(count, (T*).sizeof)) [0 .. count];
207         }
208
209         /***************************************************************
210
211                 Invoked when a specific T[] is discarded
212                 
213         ***************************************************************/
214
215         void collect (T*[] t)
216         {     
217                 if (t.length)
218                     free (t.ptr);
219         }
220
221         /***************************************************************
222
223                 Invoked when a specific T[] is discarded
224                 
225         ***************************************************************/
226
227         void collect (T* p)
228         {       
229                 if (p)
230                     free (p);
231         }
232
233         /***************************************************************
234
235                 Invoked when clear/reset is called on the host.
236                 This is a shortcut to clear everything allocated.
237
238                 Should return true if supported, or false otherwise.
239                 False return will cause a series of discrete collect
240                 calls
241                 
242         ***************************************************************/
243
244         bool collect (bool all = true)
245         {
246                 return false;
247         }
248 }        
249
250
251 /***********************************************************************
252
253         Chunk allocator
254
255         Can save approximately 30% memory for small elements (tested
256         with integer elements and a chunk size of 1000), and is at
257         least twice as fast at adding elements when compared to the
258         default allocator (approximately 50x faster with LinkedList)
259
260         Note that, due to GC behaviour, you should not configure
261         a custom allocator for containers holding anything managed
262         by the GC. For example, you cannot use a MallocAllocator
263         to manage a container of classes or strings where those
264         were allocated by the GC. Once something is owned by a GC
265         then it's lifetime must be managed by GC-managed entities
266         (otherwise the GC may think there are no live references
267         and prematurely collect container contents).
268
269         You can explicity manage the collection of keys and values
270         yourself by providing a reaper delegate. For example, if
271         you use a MallocAllocator to manage key/value pairs which
272         are themselves allocated via malloc, then you should also
273         provide a reaper delegate to collect those as required.
274
275 ***********************************************************************/
276
277 struct Chunk(T)
278 {
279         static assert (T.sizeof >= (T*).sizeof, "The Chunk allocator can only be used for data sizes of at least " ~ ((T*).sizeof).stringof[0..$-1] ~ " bytes!");
280        
281         private T[]     list;
282         private T[][]   lists;
283         private int     index;
284         private int     freelists;
285         private int     presize = 0;
286         private int     chunks = 1000;
287
288         private struct Discarded
289         {
290                 Discarded* next;
291         }
292         private Discarded* discarded;
293        
294         /***************************************************************
295
296                 set the chunk size and preallocate lists
297                 
298         ***************************************************************/
299
300         void config (int chunks, int presize)
301         {
302                 this.chunks = chunks;
303                 this.presize = presize;
304                 lists.length = presize;
305
306                 foreach (ref list; lists)
307                          list = block;
308         }
309
310         /***************************************************************
311
312                 allocate an array of T sized memory chunks
313                 
314         ***************************************************************/
315
316         T* allocate ()
317         {
318                 if (index >= list.length)
319                     if (discarded)
320                        {   
321                        auto p = discarded;
322                        discarded = p.next;
323                        return cast(T*) p;
324                        }
325                     else
326                        newlist;
327
328                 return (&list[index++]);
329         }
330
331         /***************************************************************
332
333                 allocate an array of T sized memory chunks
334                 
335         ***************************************************************/
336
337         T*[] allocate (uint count)
338         {
339                 return (cast(T**) calloc(count, (T*).sizeof)) [0 .. count];
340         }
341
342         /***************************************************************
343
344                 Invoked when a specific T[] is discarded
345                 
346         ***************************************************************/
347
348         void collect (T*[] t)
349         {     
350                 if (t.length)
351                     free (t.ptr);
352         }
353
354         /***************************************************************
355
356                 Invoked when a specific T is discarded
357                 
358         ***************************************************************/
359
360         void collect (T* p)
361         {     
362                 if (p)
363                    {
364                    assert (T.sizeof >= (T*).sizeof);
365                    auto d = cast(Discarded*) p;
366                    d.next = discarded;
367                    discarded = d;
368                    }
369         }
370
371         /***************************************************************
372
373                 Invoked when clear/reset is called on the host.
374                 This is a shortcut to clear everything allocated.
375
376                 Should return true if supported, or false otherwise.
377                 False return will cause a series of discrete collect
378                 calls
379                 
380         ***************************************************************/
381
382         bool collect (bool all = true)
383         {
384                 freelists = 0;
385                 newlist;
386                 if (all)
387                    {
388                    foreach (list; lists)
389                             free (list.ptr);
390                    lists.length = 0;
391                    }
392                 return true;
393         }
394      
395         /***************************************************************
396
397                 list manager
398                 
399         ***************************************************************/
400
401         private void newlist ()
402         {
403                 index = 0;
404                 if (freelists >= lists.length)
405                    {
406                    lists.length = lists.length + 1;
407                    lists[$-1] = block;
408                    }
409                 list = lists[freelists++];
410         }
411
412         /***************************************************************
413
414                 list allocator
415                 
416         ***************************************************************/
417
418         private T[] block ()
419         {
420                 return (cast(T*) calloc (chunks, T.sizeof)) [0 .. chunks];
421         }
422 }        
423
424 /***********************************************************************
425
426         GCChunk allocator
427
428         Like the Chunk allocator, this allocates elements in chunks,
429         but allows you to allocate elements that can have GC pointers.
430
431         Tests have shown about a 60% speedup when using the GC chunk
432         allocator for a Hashmap!(int, int).
433
434 ***********************************************************************/
435 struct GCChunk(T, uint chunkSize)
436 {
437     static if(T.sizeof < (void*).sizeof)
438     {
439         static assert(false, "Error, allocator for " ~ T.stringof ~ " failed to instantiate");
440     }
441
442     /**
443      * This is the form used to link recyclable elements together.
444      */
445     struct element
446     {
447         element *next;
448     }
449
450     /**
451      * A chunk of elements
452      */
453     struct chunk
454     {
455         /**
456          * The next chunk in the chain
457          */
458         chunk *next;
459
460         /**
461          * The previous chunk in the chain.  Required for O(1) removal
462          * from the chain.
463          */
464         chunk *prev;
465
466         /**
467          * The linked list of free elements in the chunk.  This list is
468          * amended each time an element in this chunk is freed.
469          */
470         element *freeList;
471
472         /**
473          * The number of free elements in the freeList.  Used to determine
474          * whether this chunk can be given back to the GC
475          */
476         uint numFree;
477
478         /**
479          * The elements in the chunk.
480          */
481         T[chunkSize] elems;
482
483         /**
484          * Allocate a T* from the free list.
485          */
486         T *allocateFromFree()
487         {
488             element *x = freeList;
489             freeList = x.next;
490             //
491             // clear the pointer, this clears the element as if it was
492             // newly allocated
493             //
494             x.next = null;
495             numFree--;
496             return cast(T*)x;
497         }
498
499         /**
500          * deallocate a T*, send it to the free list
501          *
502          * returns true if this chunk no longer has any used elements.
503          */
504         bool deallocate(T *t)
505         {
506             //
507             // clear the element so the GC does not interpret the element
508             // as pointing to anything else.
509             //
510             memset(t, 0, (T).sizeof);
511             element *x = cast(element *)t;
512             x.next = freeList;
513             freeList = x;
514             return (++numFree == chunkSize);
515         }
516     }
517
518     /**
519      * The chain of used chunks.  Used chunks have had all their elements
520      * allocated at least once.
521      */
522     chunk *used;
523
524     /**
525      * The fresh chunk.  This is only used if no elements are available in
526      * the used chain.
527      */
528     chunk *fresh;
529
530     /**
531      * The next element in the fresh chunk.  Because we don't worry about
532      * the free list in the fresh chunk, we need to keep track of the next
533      * fresh element to use.
534      */
535     uint nextFresh;
536
537     /**
538      * Allocate a T*
539      */
540     T* allocate()
541     {
542         if(used !is null && used.numFree > 0)
543         {
544             //
545             // allocate one element of the used list
546             //
547             T* result = used.allocateFromFree();
548             if(used.numFree == 0)
549                 //
550                 // move used to the end of the list
551                 //
552                 used = used.next;
553             return result;
554         }
555
556         //
557         // no used elements are available, allocate out of the fresh
558         // elements
559         //
560         if(fresh is null)
561         {
562             fresh = new chunk;
563             nextFresh = 0;
564         }
565
566         T* result = &fresh.elems[nextFresh];
567         if(++nextFresh == chunkSize)
568         {
569             if(used is null)
570             {
571                 used = fresh;
572                 fresh.next = fresh;
573                 fresh.prev = fresh;
574             }
575             else
576             {
577                 //
578                 // insert fresh into the used chain
579                 //
580                 fresh.prev = used.prev;
581                 fresh.next = used;
582                 fresh.prev.next = fresh;
583                 fresh.next.prev = fresh;
584                 if(fresh.numFree != 0)
585                 {
586                     //
587                     // can recycle elements from fresh
588                     //
589                     used = fresh;
590                 }
591             }
592             fresh = null;
593         }
594         return result;
595     }
596
597     T*[] allocate(uint count)
598     {
599         return new T*[count];
600     }
601
602
603     /**
604      * free a T*
605      */
606     void collect(T* t)
607     {
608         //
609         // need to figure out which chunk t is in
610         //
611         chunk *cur = cast(chunk *)GC.addrOf(t);
612
613         if(cur !is fresh && cur.numFree == 0)
614         {
615             //
616             // move cur to the front of the used list, it has free nodes
617             // to be used.
618             //
619             if(cur !is used)
620             {
621                 if(used.numFree != 0)
622                 {
623                     //
624                     // first, unlink cur from its current location
625                     //
626                     cur.prev.next = cur.next;
627                     cur.next.prev = cur.prev;
628
629                     //
630                     // now, insert cur before used.
631                     //
632                     cur.prev = used.prev;
633                     cur.next = used;
634                     used.prev = cur;
635                     cur.prev.next = cur;
636                 }
637                 used = cur;
638             }
639         }
640
641         if(cur.deallocate(t))
642         {
643             //
644             // cur no longer has any elements in use, it can be deleted.
645             //
646             if(cur.next is cur)
647             {
648                 //
649                 // only one element, don't free it.
650                 //
651             }
652             else
653             {
654                 //
655                 // remove cur from list
656                 //
657                 if(used is cur)
658                 {
659                     //
660                     // update used pointer
661                     //
662                     used = used.next;
663                 }
664                 cur.next.prev = cur.prev;
665                 cur.prev.next = cur.next;
666                 delete cur;
667             }
668         }
669     }
670
671     void collect(T*[] t)
672     {
673         if(t)
674             delete t;
675     }
676
677     /**
678      * Deallocate all chunks used by this allocator.  Depends on the GC to do
679      * the actual collection
680      */
681     bool collect(bool all = true)
682     {
683         used = null;
684
685         //
686         // keep fresh around
687         //
688         if(fresh !is null)
689         {
690             nextFresh = 0;
691             fresh.freeList = null;
692         }
693
694         return true;
695     }
696
697 }
698
699 /***********************************************************************
700
701         aliases to the correct Default allocator depending on how big
702         the type is.  It makes less sense to use a GCChunk allocator
703         if the type is going to be larger than a page (currently there
704         is no way to get the page size from the GC, so we assume 4096
705         bytes).  If not more than one unit can fit into a page, then
706         we use the default GC allocator.
707
708 ***********************************************************************/
709 template DefaultCollect(T)
710 {
711     static if((T).sizeof + ((void*).sizeof * 3) + uint.sizeof >= 4095 / 2)
712     {
713         alias Collect!(T) DefaultCollect;
714     }
715     else
716     {
717         alias GCChunk!(T, (4095 - ((void *).sizeof * 3) - uint.sizeof) / (T).sizeof) DefaultCollect;
718     }
719     // TODO: see if we can automatically figure out whether a type has
720     // any pointers in it, this would allow automatic usage of the
721     // Chunk allocator for added speed.
722 }
723 }
724
725
726
727
728 private import tango.util.container.model.IContainer;
729
730
731 class HashSet (V, alias Heap = Container.DefaultCollect)
732 {
733 public alias Slink!(V)  Type;
734
735 private alias Type      *Ref;
736
737 private alias Heap!(Type) Alloc;
738 }