1 module tagion.betterC.utils.Memory;
2 
3 import core.stdc.string : memcpy;
4 import std.conv : emplace;
5 import std.traits : ForeachType, PointerTarget, Unqual, isArray, isPointer;
6 import tagion.betterC.utils.platform;
7 
8 private import tagion.crypto.secp256k1.c.secp256k1;
9 private import tagion.crypto.secp256k1.c.secp256k1_ecdh;
10 
11 @nogc:
12 
13 version (memtrace) {
14     enum memalloc_format = "#%p:%06d\t\t\t\t%04d %c %s\n";
15     static const memalloc_trace = memalloc_format.ptr;
16     enum memfree_format = "#%p:000000\t\t\t\t%04d %c %s\n";
17     static const memfree_trace = memfree_format.ptr;
18     enum mempos_format = "#%p:%06d\t\t\t\t%d:%s\n";
19     static const mempos = mempos_format.ptr;
20     static uint block;
21 }
22 
23 @trusted
24 T create(T)(const size_t size, string file = __FILE__, size_t line = __LINE__) if (isArray!T) {
25     alias BaseT = ForeachType!T;
26     auto mem = calloc(size, BaseT.sizeof);
27     version (memtrace) {
28         const _size = size * BaseT.sizeof;
29         printf(memalloc_trace, mem, _size, block, 'a', T.stringof.ptr);
30         printf(mempos, mem, _size, line, file.ptr);
31         block++;
32     }
33     return (cast(BaseT*) mem)[0 .. size];
34 }
35 
36 @trusted
37 void create(T)(ref T data, const size_t size, string file = __FILE__, size_t line = __LINE__) if (isArray!T)
38 in {
39     assert(data is null);
40 }
41 do {
42     alias BaseT = ForeachType!T;
43     auto mem = calloc(size, BaseT.sizeof);
44     version (memtrace) {
45         const _size = size * BaseT.sizeof;
46         printf(memalloc_trace, mem, _size, block, 'A', T.stringof.ptr);
47         printf(mempos, mem, _size, line, file.ptr);
48         block++;
49 
50     }
51     data = (cast(BaseT*) mem)[0 .. size];
52 }
53 
54 @trusted
55 void create(U)(ref U[] data, const(U[]) src, string file = __FILE__, size_t line = __LINE__)
56 in {
57     assert(data is null);
58 }
59 do {
60     alias BaseU = Unqual!U;
61     auto mem = calloc(src.length, U.sizeof);
62     version (memtrace) {
63         printf(memalloc_trace, mem, src.length * U.sizeof, block, 'B', (U[]).stringof.ptr);
64         printf(mempos, mem, 0, line, file.ptr);
65         block++;
66 
67     }
68     auto temp = (cast(BaseU*) mem)[0 .. src.length];
69     temp[0 .. src.length] = src;
70     data = cast(U[]) temp;
71 }
72 
73 @trusted
74 T* create(T, Args...)(Args args, string file = __FILE__, size_t line = __LINE__) if (is(T == struct)) {
75     auto mem = calloc(T.sizeof, 1);
76     version (memtrace) {
77         const _size = T.sizeof;
78         printf(memalloc_trace, mem, _size, block, 'S', T.stringof.ptr);
79         printf(mempos, mem, _size, line, file.ptr);
80         block++;
81     }
82     auto result = cast(T*) mem;
83     emplace!T(result, args);
84     return result;
85 }
86 
87 @trusted
88 T create(T)(string file = __FILE__, size_t line = __LINE__) if (isPointer!T) {
89     auto mem = calloc(PointerTarget!(T).sizeof, 1);
90     version (memtrace) {
91         const _size = PointerTarget!(T).sizeof;
92         printf(memalloc_trace, mem, _size, block, '*', T.stringof.ptr);
93         printf(mempos, mem, _size, line, file.ptr);
94         block++;
95 
96     }
97     return cast(T) mem;
98 }
99 
100 @trusted
101 void resize(T)(ref T data, const size_t len, string file = __FILE__, size_t line = __LINE__) if (isArray!T) {
102     alias BaseT = ForeachType!T;
103     const size = len * BaseT.sizeof;
104     auto mem = realloc(cast(void*) data.ptr, size);
105     version (memtrace) {
106         printf(memfree_trace, &data, block, 'R', T.stringof.ptr);
107         printf(memalloc_trace, mem, size, block, 'R', T.stringof.ptr);
108         printf(mempos, mem, size, line, file.ptr);
109     }
110     data = (cast(BaseT*) mem)[0 .. len];
111 }
112 
113 @trusted
114 void dispose(T)(ref T die, string file = __FILE__, size_t line = __LINE__) if (isArray!T) {
115     if (die !is null) {
116         static if (__traits(compiles, die[0].dispose)) {
117             foreach (ref d; die) {
118                 d.dispose;
119             }
120         }
121         version (memtrace) {
122             block--;
123             printf(memfree_trace, die.ptr, block, 'd', T.stringof.ptr);
124             printf(mempos, die.ptr, 0, line, file.ptr);
125         }
126         free(cast(void*) die.ptr);
127         die = null;
128     }
129 }
130 
131 @trusted
132 void dispose(bool OWNS = true, T)(ref T die, string file = __FILE__, size_t line = __LINE__) if (isPointer!T) {
133     if (die !is null) {
134         static if (OWNS && __traits(compiles, (*die).dispose)) {
135             (*die).dispose;
136         }
137         version (memtrace) {
138             block--;
139             printf(memfree_trace, die, block, 'D', T.stringof.ptr);
140             printf(mempos, die, 0, line, file.ptr);
141         }
142         free(die);
143         die = null;
144     }
145 }
146 
147 @trusted
148 void memcpy_wrapper(T)(ref T desination, T source) {
149     if (desination.length == source.length) {
150         memcpy(desination, source, source.length);
151     }
152 }
153 
154 enum SECP256K1 : uint {
155     FLAGS_TYPE_MASK = SECP256K1_FLAGS_TYPE_MASK,
156     FLAGS_TYPE_CONTEXT = SECP256K1_FLAGS_TYPE_CONTEXT,
157     FLAGS_TYPE_COMPRESSION = SECP256K1_FLAGS_TYPE_COMPRESSION,
158     /** The higher bits contain the actual data. Do not use directly. */
159     FLAGS_BIT_CONTEXT_VERIFY = SECP256K1_FLAGS_BIT_CONTEXT_VERIFY,
160     FLAGS_BIT_CONTEXT_SIGN = SECP256K1_FLAGS_BIT_CONTEXT_SIGN,
161     FLAGS_BIT_COMPRESSION = FLAGS_BIT_CONTEXT_SIGN,
162 
163     /** Flags to pass to secp256k1_context_create. */
164     CONTEXT_VERIFY = SECP256K1_CONTEXT_VERIFY,
165     CONTEXT_SIGN = SECP256K1_CONTEXT_SIGN,
166     CONTEXT_NONE = SECP256K1_CONTEXT_NONE,
167 
168     /** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
169     EC_COMPRESSED = SECP256K1_EC_COMPRESSED,
170     EC_UNCOMPRESSED = SECP256K1_EC_UNCOMPRESSED,
171 
172     /** Prefix byte used to tag various encoded curvepoints for specific purposes */
173     TAG_PUBKEY_EVEN = SECP256K1_TAG_PUBKEY_EVEN,
174     TAG_PUBKEY_ODD = SECP256K1_TAG_PUBKEY_ODD,
175     TAG_PUBKEY_UNCOMPRESSED = SECP256K1_TAG_PUBKEY_UNCOMPRESSED,
176     TAG_PUBKEY_HYBRID_EVEN = SECP256K1_TAG_PUBKEY_HYBRID_EVEN,
177     TAG_PUBKEY_HYBRID_ODD = SECP256K1_TAG_PUBKEY_HYBRID_ODD
178 }
179 
180 @trusted
181 bool randomize(immutable(ubyte[]) seed)
182 in {
183     assert(seed.length == 32 || seed is null);
184 }
185 do {
186     secp256k1_context* _ctx;
187     // const int flag = 0;
188     _ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
189     //        auto ctx=getContext();
190     // immutable(ubyte)* _seed = seed.ptr;
191     return secp256k1_context_randomize(_ctx, &seed[0]) == 1;
192 }
193 
194 unittest {
195     { // Check Array
196         uint[] array;
197         const(uint[6]) table = [5, 6, 7, 3, 2, 1];
198         array.create(table.length);
199         scope (exit) {
200             array.dispose;
201             assert(array.length == 0);
202             assert(array is null);
203         }
204 
205         foreach (a; array) {
206             assert(a == a.init);
207         }
208 
209         foreach (i, c; table) {
210             array[i] = c;
211         }
212 
213         foreach (i, a; array) {
214             assert(a == table[i]);
215         }
216         assert(array.length == table.length);
217     }
218 
219     { // Struct
220         struct S {
221             bool b;
222             int x;
223         }
224 
225         auto s = create!S(true, 42);
226         scope (exit) {
227             s.dispose;
228         }
229 
230         assert(s.b == true);
231         assert(s.x == 42);
232     }
233 
234 }