1 /*
2     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
3     Authors:   Adam Búš
4 */
5 module btl.internal.gc;
6 
7 
8 
9 
10 version(D_BetterC){
11 }
12 else{
13     version(BTL_GC_RANGE_COUNT)
14         public __gshared int _conter_gc_ranges = 0;
15 
16 
17     version(BTL_GC_RANGE_TRACK)
18         package __gshared const(void)[][] _gc_ranges = null;
19 
20 
21     shared static ~this(){
22         version(BTL_GC_RANGE_COUNT){
23             import std.conv;
24             if(_conter_gc_ranges != 0)
25                 assert(0, "BTL_GC_RANGE_COUNT: " ~ _conter_gc_ranges.to!string ~ " != 0");
26         }
27 
28 
29         version(BTL_GC_RANGE_TRACK){
30             foreach(const(void)[] gcr; _gc_ranges)
31                 assert(gcr.length == 0);
32         }
33     }
34 }
35 
36 //same as GC.addRange but `pure nothrow @trusted @nogc` and with debug testing
37 public void gcAddRange(T)(const T[] data)pure nothrow @trusted @nogc{
38     gcAddRange(data.ptr, data.length * T.sizeof);
39 }
40 public void gcAddRange(const void* data, const size_t length)pure nothrow @trusted @nogc{
41     version(D_BetterC){
42     }
43     else{
44         import btl.traits.assume;
45 
46         assumePure(function void(const void* ptr, const size_t len){
47             import core.memory: GC;
48             GC.addRange(ptr, len);
49         })(data, length);
50 
51 
52         assert(data !is null);
53         assert(length > 0);
54 
55         assumePureNoGc(function void(const void* data, const size_t length)@trusted{
56             version(BTL_GC_RANGE_COUNT){
57                 import core.atomic;
58                 atomicFetchAdd!(MemoryOrder.raw)(_conter_gc_ranges, 1);
59             }
60 
61 
62 
63             version(BTL_GC_RANGE_TRACK){
64                 foreach(const void[] gcr; _gc_ranges){
65                     if(gcr.length == 0)
66                         continue;
67 
68                     const void* gcr_end = (gcr.ptr + gcr.length);
69                     assert(!(data <= gcr.ptr && gcr.ptr < (data + length)));
70                     assert(!(data < gcr_end && gcr_end <= (data + length)));
71                     assert(!(gcr.ptr <= data && (data + length) <= gcr_end));
72                 }
73 
74                 foreach(ref const(void)[] gcr; _gc_ranges){
75                     if(gcr.length == 0){
76                         gcr = data[0 .. length];
77                         return;
78                     }
79                 }
80 
81                 _gc_ranges ~= data[0 .. length];
82 
83             }
84 
85         })(data, length);
86     }
87 }
88 
89 //same as GC.removeRange but `pure nothrow @trusted @nogc` and with debug testing
90 public void gcRemoveRange(T)(const T[] data)pure nothrow @trusted @nogc{
91     gcRemoveRange(data.ptr);
92 }
93 
94 public void gcRemoveRange(const void* data)pure nothrow @trusted @nogc{
95     version(D_BetterC){
96     }
97     else{
98         import btl.traits.assume;
99 
100         assumePure(function void(const void* ptr){
101             import core.memory: GC;
102             GC.removeRange(ptr);
103         })(data);
104 
105         assert(data !is null);
106 
107         assumePure(function void(const void* data)@trusted{
108             version(BTL_GC_RANGE_COUNT){
109                 import core.atomic;
110                 atomicFetchSub!(MemoryOrder.raw)(_conter_gc_ranges, 1);
111             }
112 
113             version(BTL_GC_RANGE_TRACK){
114                 foreach(ref const(void)[] gcr; _gc_ranges){
115                     if(gcr.ptr is data){
116                         gcr = null;
117                         return;
118                     }
119                     const void* gcr_end = (gcr.ptr + gcr.length);
120                     assert(!(gcr.ptr <= data && data < gcr_end));
121                 }
122 
123                 assert(0, "BTL_GC_RANGE_TRACK: missing gc range");
124             }
125         })(data);
126     }
127 }