33Source: $(PHOBOSSRC std/experimental/allocator/building_blocks/kernighan_ritchie.d)
44*/
55module std.experimental.allocator.building_blocks.kernighan_ritchie ;
6- import std.experimental.allocator.building_blocks.null_allocator :
7- NullAllocator;
6+ import std.experimental.allocator.building_blocks.null_allocator ;
87
98// debug = KRRegion;
109debug (KRRegion) import std.stdio ;
@@ -111,18 +110,21 @@ struct KRRegion(ParentAllocator = NullAllocator)
111110
112111 this (this ) @disable ;
113112
113+ pure nothrow @trusted @nogc
114114 void [] payload () inout
115115 {
116116 return (cast (ubyte * ) &this )[0 .. size];
117117 }
118118
119+ pure nothrow @trusted @nogc
119120 bool adjacent (in Node* right) const
120121 {
121122 assert (right);
122123 auto p = payload;
123124 return p.ptr < right && right < p.ptr + p.length + Node.sizeof;
124125 }
125126
127+ pure nothrow @trusted @nogc
126128 bool coalesce (void * memoryEnd = null )
127129 {
128130 // Coalesce the last node before the memory end with any possible gap
@@ -139,6 +141,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
139141 return true ;
140142 }
141143
144+ @safe
142145 Tuple ! (void [], Node* ) allocateHere(size_t bytes)
143146 {
144147 assert (bytes >= Node.sizeof);
@@ -152,7 +155,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
152155 if (leftover >= Node.sizeof)
153156 {
154157 // There's room for another node
155- auto newNode = cast (Node* ) ((cast (ubyte * ) &this ) + bytes);
158+ auto newNode = (() @trusted => cast (Node* ) ((cast (ubyte * ) &this ) + bytes))( );
156159 newNode.size = leftover;
157160 newNode.next = next == &this ? newNode : next;
158161 assert (next);
@@ -358,7 +361,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
358361 // / Ditto
359362 static if (! is (ParentAllocator == NullAllocator)
360363 && hasMember! (ParentAllocator, " deallocate" ))
361- ~this ()
364+ @trusted ~this ()
362365 {
363366 parent.deallocate(payload);
364367 }
@@ -396,6 +399,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
396399
397400 Returns: A word-aligned buffer of `n` bytes, or `null`.
398401 */
402+ @safe
399403 void [] allocate (size_t n)
400404 {
401405 if (! n || ! root) return null ;
@@ -413,7 +417,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
413417 immutable balance = root.size - actualBytes;
414418 if (balance >= Node.sizeof)
415419 {
416- auto newRoot = cast (Node* ) (result + actualBytes);
420+ auto newRoot = (() @trusted => cast (Node* ) (result + actualBytes))( );
417421 newRoot.next = root.next;
418422 newRoot.size = balance;
419423 root = newRoot;
@@ -423,7 +427,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
423427 root = null ;
424428 switchToFreeList;
425429 }
426- return result[0 .. n];
430+ return (() @trusted => result[0 .. n])() ;
427431 }
428432
429433 // Not enough memory, switch to freelist mode and fall through
@@ -554,6 +558,7 @@ struct KRRegion(ParentAllocator = NullAllocator)
554558 at the front of the free list. These blocks get coalesced, whether
555559 `allocateAll` succeeds or fails due to fragmentation.
556560 */
561+
557562 void [] allocateAll ()
558563 {
559564 if (regionMode) switchToFreeList;
@@ -647,7 +652,7 @@ fronting the GC allocator.
647652 import std.experimental.allocator.gc_allocator : GCAllocator;
648653 import std.typecons : Ternary;
649654 // KRRegion fronting a general-purpose allocator
650- align (KRRegion ! ().alignment) ubyte [1024 * 128 ] buf;
655+ ubyte [1024 * 128 ] buf;
651656 auto alloc = fallbackAllocator(KRRegion! ()(buf), GCAllocator.instance);
652657 auto b = alloc.allocate(100 );
653658 assert (b.length == 100 );
@@ -669,6 +674,7 @@ it actually returns memory to the operating system when possible.
669674 import std.algorithm.comparison : max;
670675 import std.experimental.allocator.building_blocks.allocator_list
671676 : AllocatorList;
677+ import std.experimental.allocator.gc_allocator : GCAllocator;
672678 import std.experimental.allocator.mmap_allocator : MmapAllocator;
673679 AllocatorList! (n => KRRegion! MmapAllocator(max(n * 16 , 1024 * 1024 ))) alloc;
674680}
@@ -678,6 +684,7 @@ it actually returns memory to the operating system when possible.
678684 import std.algorithm.comparison : max;
679685 import std.experimental.allocator.building_blocks.allocator_list
680686 : AllocatorList;
687+ import std.experimental.allocator.gc_allocator : GCAllocator;
681688 import std.experimental.allocator.mallocator : Mallocator;
682689 import std.typecons : Ternary;
683690 /*
@@ -710,6 +717,7 @@ it actually returns memory to the operating system when possible.
710717 import std.algorithm.comparison : max;
711718 import std.experimental.allocator.building_blocks.allocator_list
712719 : AllocatorList;
720+ import std.experimental.allocator.gc_allocator : GCAllocator;
713721 import std.experimental.allocator.mmap_allocator : MmapAllocator;
714722 import std.typecons : Ternary;
715723 /*
@@ -742,7 +750,6 @@ it actually returns memory to the operating system when possible.
742750 }
743751}
744752
745- version (StdUnittest)
746753@system unittest
747754{
748755 import std.algorithm.comparison : max;
@@ -754,16 +761,17 @@ version (StdUnittest)
754761 n => KRRegion! GCAllocator(max(n * 16 , 1024 * 1024 )))());
755762}
756763
757- @system unittest
764+ @trusted unittest
758765{
759766 import std.experimental.allocator.gc_allocator : GCAllocator;
760-
761767 auto alloc = KRRegion! GCAllocator(1024 * 1024 );
762768
769+
770+
763771 void [][] array;
764772 foreach (i; 1 .. 4 )
765773 {
766- array ~= alloc.allocate(i);
774+ array ~= (() nothrow @safe => alloc.allocate(i))( );
767775 assert (array[$ - 1 ].length == i);
768776 }
769777 () nothrow @nogc { alloc.deallocate(array[1 ]); }();
@@ -778,11 +786,11 @@ version (StdUnittest)
778786 import std.typecons : Ternary;
779787 auto alloc = KRRegion! ()(
780788 cast (ubyte [])(GCAllocator.instance.allocate(1024 * 1024 )));
781- const store = alloc.allocate(KRRegion! ().sizeof);
789+ const store = (() pure nothrow @safe @nogc => alloc.allocate(KRRegion! ().sizeof))( );
782790 auto p = cast (KRRegion! ()* ) store.ptr;
783- import core.lifetime : emplace;
784791 import core.stdc.string : memcpy;
785- import std.conv : text;
792+ import std.algorithm.mutation : move;
793+ import std.conv : text, emplace;
786794
787795 memcpy(p, &alloc, alloc.sizeof);
788796 emplace(&alloc);
@@ -791,7 +799,7 @@ version (StdUnittest)
791799 foreach (i; 0 .. array.length)
792800 {
793801 auto length = 100 * i + 1 ;
794- array[i] = p.allocate(length);
802+ array[i] = (() pure nothrow @safe @nogc => p.allocate(length))( );
795803 assert (array[i].length == length, text(array[i].length));
796804 assert ((() pure nothrow @safe @nogc => p.owns(array[i]))() == Ternary.yes);
797805 }
@@ -820,14 +828,16 @@ version (StdUnittest)
820828 assert (p.length == 1024 * 1024 );
821829}
822830
831+
823832@system unittest
824833{
825- import std.random : randomCover;
834+ import std.experimental.allocator.building_blocks ;
835+ import std.random ;
826836 import std.typecons : Ternary;
827837
828838 // Both sequences must work on either system
829839
830- // A sequence of allocs which generates the error described in https://issues.dlang.org/show_bug.cgi?id= 16564
840+ // A sequence of allocs which generates the error described in issue 16564
831841 // that is a gap at the end of buf from the perspective of the allocator
832842
833843 // for 64 bit systems (leftover balance = 8 bytes < 16)
@@ -837,16 +847,16 @@ version (StdUnittest)
837847 int [] sizes32 = [81412 , 107068 , 49892 , 23768 ];
838848
839849
840- void test (int [] sizes)
850+ @system void test(int [] sizes)
841851 {
842852 align (size_t .sizeof) ubyte [256 * 1024 ] buf;
843- auto a = KRRegion ! () (buf);
853+ auto a = (() @trusted => createAllocator (buf))( );
844854
845855 void [][] bufs;
846856
847857 foreach (size; sizes)
848858 {
849- bufs ~= a.allocate(size);
859+ bufs ~= (() pure nothrow @safe @nogc => a.allocate(size))( );
850860 }
851861
852862 foreach (b; bufs.randomCover)
@@ -857,12 +867,22 @@ version (StdUnittest)
857867 assert ((() pure nothrow @safe @nogc => a.empty)() == Ternary.yes);
858868 }
859869
860- test(sizes64);
861- test(sizes32);
870+ () @trusted {
871+ test(sizes64);
872+ test(sizes32);
873+ }();
862874}
863875
864- @system unittest
876+ @system KRRegion! NullAllocator createAllocator(ubyte [] buf)
877+ {
878+ return KRRegion! NullAllocator(buf);
879+ }
880+
881+
882+ @safe unittest
865883{
884+ import std.experimental.allocator.building_blocks ;
885+ import std.random ;
866886 import std.typecons : Ternary;
867887
868888 // For 64 bits, we allocate in multiples of 8, but the minimum alloc size is 16.
@@ -886,11 +906,11 @@ version (StdUnittest)
886906
887907 foreach (size; sizes)
888908 {
889- bufs ~= a.allocate(size);
909+ bufs ~= (() pure nothrow @safe @nogc => a.allocate(size))( );
890910 }
891911
892912 () nothrow @nogc { a.deallocate(bufs[1 ]); }();
893- bufs ~= a.allocate(sizes[1 ] - word);
913+ bufs ~= (() pure nothrow @safe @nogc => a.allocate(sizes[1 ] - word))( );
894914
895915 () nothrow @nogc { a.deallocate(bufs[0 ]); }();
896916 foreach (i; 2 .. bufs.length)
@@ -916,7 +936,7 @@ version (StdUnittest)
916936@system unittest
917937{ import std.typecons : Ternary;
918938
919- align (KRRegion ! ().alignment) ubyte [1024 ] b;
939+ ubyte [1024 ] b;
920940 auto alloc = KRRegion! ()(b);
921941
922942 auto k = alloc.allocate(128 );
0 commit comments