Skip to content

Commit 65e0563

Browse files
authored
add mir.variant and mir.rc (#224)
1 parent 2a337ae commit 65e0563

File tree

8 files changed

+404
-46
lines changed

8 files changed

+404
-46
lines changed

doc/Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ PACKAGE_mir = \
3636
small_string \
3737
small_array \
3838
polynomial \
39-
format\
40-
parse\
41-
appender\
42-
exception\
39+
format \
40+
parse \
41+
appender \
42+
exception \
43+
variant \
4344

4445
PACKAGE_mir_algorithm = iteration setops
4546
PACKAGE_mir_array = allocation

index.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ $(BOOKTABLE ,
2323
$(TR $(TDNW $(MREF mir,math,constant)) $(TD Math constants))
2424
$(TR $(TDNW $(MREF mir,polynomial)) $(TD Polynomial ref-counted structure))
2525
$(LEADINGROW Reference counting)
26+
$(TR $(TDNW $(MREF mir,rc)) $(TD Reference counting package and RC conversion utilities.))
2627
$(TR $(TDNW $(MREF mir,rc,array)) $(TD Thread safe reference count array and the iterator to adopt it to ndslice.))
2728
$(TR $(TDNW $(MREF mir,rc,ptr)) $(TD Thread safe reference count pointer with polymorphism support for strucs and objects.))
2829
$(TR $(TDNW $(MREF mir,rc,slim_ptr)) $(TD Thread safe reference count pointer for strucs and objects.))
@@ -40,6 +41,7 @@ $(BOOKTABLE ,
4041
$(LEADINGROW Interconnection with other languages)
4142
$(TR $(TDNW $(MREF mir,ndslice,connect,cpython)) $(TD Utilities for $(HTTPS docs.python.org/3/c-api/buffer.html, Python Buffer Protocol)))
4243
$(LEADINGROW Accessories)
44+
$(TR $(TDNW $(MREF mir,variant)) $(TD Variant Type (aka Algebraic Type) with clever member access))
4345
$(TR $(TDNW $(MREF mir,exception)) $(TD @nogc MirException with formatting))
4446
$(TR $(TDNW $(MREF mir,format)) $(TD @nogc Formatting Utilities))
4547
$(TR $(TDNW $(MREF mir,parse)) $(TD @nogc Parsing Utilities))

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ mir_algorithm_src = [
6767
'source/mir/small_array.d',
6868
'source/mir/small_string.d',
6969
'source/mir/type_info.d',
70+
'source/mir/variant.d',
7071
]
7172

7273
mir_algorithm_lib = library(meson.project_name(),

source/mir/rc/array.d

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import mir.rc.context;
99
import mir.type_info;
1010
import std.traits;
1111

12-
private static immutable allocationExcMsg = "mir_rcarray: out of memory error.";
12+
package static immutable allocationExcMsg = "mir_rcarray: out of memory error.";
1313

1414
version (D_Exceptions)
1515
{
1616
import core.exception: OutOfMemoryError;
17-
private static immutable allocationError = new OutOfMemoryError(allocationExcMsg);
17+
package static immutable allocationError = new OutOfMemoryError(allocationExcMsg);
1818
}
1919

2020
/++
@@ -27,16 +27,16 @@ The implementation never adds roots into the GC.
2727
struct mir_rcarray(T)
2828
{
2929
///
30-
private T* _payload;
31-
private ref inout(mir_rc_context) context() inout scope return pure nothrow @nogc @trusted @property
30+
package T* _payload;
31+
package ref inout(mir_rc_context) context() inout scope return pure nothrow @nogc @trusted @property
3232
{
3333
assert(_payload);
3434
return (cast(inout(mir_rc_context)*)_payload)[-1];
3535
}
36-
private void _reset() { _payload = null; }
36+
package void _reset() { _payload = null; }
3737

38-
private alias ThisTemplate = .mir_rcarray;
39-
private alias _thisPtr = _payload;
38+
package alias ThisTemplate = .mir_rcarray;
39+
package alias _thisPtr = _payload;
4040

4141
///
4242
void proxySwap(ref typeof(this) rhs) pure nothrow @nogc @safe
@@ -176,11 +176,11 @@ struct mir_rcarray(T)
176176

177177
static if (isImplicitlyConvertible!(const T, T))
178178
static if (isImplicitlyConvertible!(const Unqual!T, T))
179-
private alias V = const Unqual!T;
179+
package alias V = const Unqual!T;
180180
else
181-
private alias V = const T;
181+
package alias V = const T;
182182
else
183-
private alias V = T;
183+
package alias V = T;
184184

185185
}
186186

@@ -215,7 +215,7 @@ unittest
215215
static assert(is(typeof(fs) == Slice!(double*)));
216216
}
217217

218-
private template LikeArray(Range)
218+
package template LikeArray(Range)
219219
{
220220
static if (__traits(identifier, Range) == "mir_slice")
221221
{

source/mir/rc/package.d

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,153 @@
11
/++
22
$(H1 Thread-safe reference-counted arrays and pointers)
33
4-
Publicly imports $(MREF mir,rc,array) and $(MREF mir,rc,ptr).
4+
Mir provides two kinds of ref-counting pointers and two kinds of ref-counted arrays.
5+
6+
The first kind pointer is `RCPtr`, which consists of a pointer to the context and pointer to the value.`RCPtr` supports structural and object polymorphism. It allows getting members with the same context as the root.
7+
The second kind is `SlimRCPtr`, which consist only from a pointer to the value. The context for `SlimRCPtr`is computed using a fixed-length memory shift from the pointer to the value.
8+
`SlimRCPtr` can be converted to an `RCPtr` and to an `RCArray` of the one element.
9+
10+
`RCArray` is an array type without range primitives. It's length can't be reduced after construction.In the other hand, `Slice!(RCI!(T))` is an ndslice with all random-access range primitives.`RCI` is an iterator, which consists of `RCArray` and the pointer to the current element.
11+
`RCArray!T` can be converted or moved to `Slice!(RCI!(T))` using `.asSlice` or `.moveToSlice` methods respectively.
12+
13+
$(RED `RCArray!T` aliases itself to a common D array slice. This feature may cause a segmentation fault in safe code if used without DIP1000.)
14+
15+
`RCPtr!T` can be constructed from an element index and `RCArray!T` / `Slice!(RCI!(T))`.
16+
17+
The package publicly imports $(MREF mir,rc,array), $(MREF mir,rc,ptr), and $(MREF mir,rc,slim_ptr).
18+
19+
See_also: $(MREF mir,ndslice).
520
+/
621
module mir.rc;
722

823
public import mir.rc.array;
924
public import mir.rc.ptr;
1025
public import mir.rc.slim_ptr;
26+
27+
import mir.ndslice.slice;
28+
29+
/++
30+
Returns: shared pointer constructed from the slim shared pointer.
31+
32+
The function has zero computation cost.
33+
+/
34+
RCPtr!F toRCPtr(F)(return SlimRCPtr!F contextAndValue) @trusted
35+
{
36+
typeof(return) ret;
37+
ret._value = contextAndValue._value;
38+
ret._context = &contextAndValue.context();
39+
contextAndValue._value = null;
40+
return ret;
41+
}
42+
43+
///
44+
version(mir_test)
45+
@safe pure @nogc nothrow
46+
unittest
47+
{
48+
import core.lifetime: move;
49+
struct S
50+
{
51+
double e;
52+
}
53+
struct C
54+
{
55+
int i;
56+
S s;
57+
}
58+
59+
auto a = createSlimRC!C(10, S(3));
60+
auto s = a.move.toRCPtr.shareMember!"s";
61+
assert(s._counter == 1);
62+
assert(s.e == 3);
63+
}
64+
65+
/++
66+
Returns: shared pointer constructed with the `array`'s context and the value points to `array[index]`.
67+
68+
The function has zero computation cost.
69+
+/
70+
RCPtr!F toRCPtrAt(F)(return RCArray!F array, size_t index) @trusted
71+
if (!is(R == class) && !is(R == interface))
72+
in {
73+
assert(index < array.length, "toRCPtrAt: index should be less then array.length");
74+
}
75+
body {
76+
typeof(return) ret;
77+
ret._value = array._payload + index;
78+
ret._context = &array.context();
79+
array._payload = null;
80+
return ret;
81+
}
82+
83+
///
84+
version(mir_test)
85+
@safe pure @nogc nothrow
86+
unittest
87+
{
88+
struct S { double e; }
89+
90+
auto a = RCArray!S(10);
91+
a[3].e = 4;
92+
93+
auto s = a.toRCPtrAt(3);
94+
95+
assert(s._counter == 2);
96+
assert(s.e == 4);
97+
}
98+
99+
/// ditto
100+
RCPtr!F toRCPtrAt(F)(return Slice!(RCI!F) array, size_t index) @trusted
101+
if (!is(R == class) && !is(R == interface))
102+
in {
103+
assert(index < array.length, "toRCPtrAt: index should be less then array.length");
104+
}
105+
body {
106+
typeof(return) ret;
107+
ret._value = array._iterator._iterator + index;
108+
ret._context = &array._iterator._array.context();
109+
array._iterator._array._payload = null;
110+
return ret;
111+
}
112+
113+
///
114+
version(mir_test)
115+
@safe pure @nogc nothrow
116+
unittest
117+
{
118+
struct S { double e; }
119+
120+
auto a = RCArray!S(10).asSlice[5 .. $];
121+
a[3].e = 4;
122+
123+
auto s = a.toRCPtrAt(3);
124+
125+
assert(s._counter == 2);
126+
assert(s.e == 4);
127+
}
128+
129+
/++
130+
Returns: RC array length of one constructed from the slim shared pointer.
131+
132+
The function has zero computation cost.
133+
+/
134+
RCArray!F toRCArray(F)(return SlimRCPtr!F context) @trusted
135+
{
136+
typeof(return) ret;
137+
ret._payload = context._value;
138+
context._value = null;
139+
return ret;
140+
}
141+
142+
///
143+
version(mir_test)
144+
@safe pure @nogc nothrow
145+
unittest
146+
{
147+
struct S { double e; }
148+
149+
auto a = createSlimRC!S(4).toRCArray;
150+
assert(a._counter == 1);
151+
assert(a.length == 1);
152+
assert(a[0].e == 4);
153+
}

source/mir/rc/ptr.d

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import mir.rc.context;
99
import mir.type_info;
1010
import std.traits;
1111

12-
private static immutable allocationExcMsg = "mir_rcptr: out of memory error.";
13-
private static immutable getExcMsg = "mir_rcptr: trying to use null value.";
12+
package static immutable allocationExcMsg = "mir_rcptr: out of memory error.";
13+
package static immutable getExcMsg = "mir_rcptr: trying to use null value.";
1414

1515
version (D_Exceptions)
1616
{
1717
import core.exception: OutOfMemoryError, InvalidMemoryOperationError;
18-
private static immutable allocationError = new OutOfMemoryError(allocationExcMsg);
18+
package static immutable allocationError = new OutOfMemoryError(allocationExcMsg);
1919
}
2020

2121
/++
@@ -34,17 +34,17 @@ struct mir_rcptr(T)
3434

3535
///
3636
static if (is(T == class) || is(T == interface))
37-
private Unqual!T _value;
37+
package Unqual!T _value;
3838
else
39-
private T* _value;
40-
private mir_rc_context* _context;
39+
package T* _value;
40+
package mir_rc_context* _context;
4141

42-
private ref inout(mir_rc_context) context() inout scope return @trusted @property
42+
package ref inout(mir_rc_context) context() inout scope return @trusted @property
4343
{
4444
return *_context;
4545
}
4646

47-
private void _reset()
47+
package void _reset()
4848
{
4949
_value = null;
5050
_context = null;
@@ -55,7 +55,7 @@ struct mir_rcptr(T)
5555
return cast(inout(void)*) _value;
5656
}
5757

58-
private alias ThisTemplate = .mir_rcptr;
58+
package alias ThisTemplate = .mir_rcptr;
5959

6060
/// ditto
6161
alias opUnary(string op : "*") = _get_value;
@@ -122,7 +122,7 @@ struct mir_rcptr(T)
122122

123123
static if (!is(T == interface) && !__traits(isAbstractClass, T))
124124
{
125-
private this(Args...)(auto ref Args args)
125+
package this(Args...)(auto ref Args args)
126126
{
127127
() @trusted {
128128
_context = mir_rc_create(mir_get_type_info!T, 1, mir_get_payload_ptr!T);
@@ -146,28 +146,30 @@ struct mir_rcptr(T)
146146
alias RCPtr = mir_rcptr;
147147

148148
/++
149+
Returns: shared pointer of the member and the context from the current pointer.
149150
+/
150151
auto shareMember(string member, T, Args...)(return mir_rcptr!T context, auto ref Args args)
151152
{
153+
import core.lifetime: move;
152154
void foo(A)(auto ref A) {}
153155
static if (args.length)
154156
{
155157
// breaks safaty
156158
if (false) foo(__traits(getMember, context._get_value, member)(forward!args));
157-
return (()@trusted => createRCWithContext(context, __traits(getMember, context._get_value, member)(forward!args)))();
159+
return (()@trusted => createRCWithContext(__traits(getMember, context._get_value, member)(forward!args), context.move))();
158160
}
159161
else
160162
{
161163
// breaks safaty
162164
if (false) foo(__traits(getMember, context._get_value, member));
163-
return (()@trusted => createRCWithContext(context, __traits(getMember, context._get_value, member)))();
165+
return (()@trusted => createRCWithContext(__traits(getMember, context._get_value, member), context.move))();
164166
}
165167
}
166168

167169
/++
168170
Returns: shared pointer constructed with current context.
169171
+/
170-
@system .mir_rcptr!R createRCWithContext(R, F)(return const mir_rcptr!F context, return R value)
172+
@system .mir_rcptr!R createRCWithContext(R, F)(return R value, return const mir_rcptr!F context)
171173
if (is(R == class) || is(R == interface))
172174
{
173175
typeof(return) ret;
@@ -179,7 +181,7 @@ Returns: shared pointer constructed with current context.
179181
}
180182

181183
///ditto
182-
@system .mir_rcptr!R createRCWithContext(R, F)(return const mir_rcptr!F context, return ref R value)
184+
@system .mir_rcptr!R createRCWithContext(R, F)(return ref R value, return const mir_rcptr!F context)
183185
if (!is(R == class) && !is(R == interface))
184186
{
185187
typeof(return) ret;
@@ -197,21 +199,24 @@ Provides polymorphism abilities for classes and structures with `alias this` syn
197199
mir_rcptr!R castTo(R, T)(return mir_rcptr!T context) @trusted
198200
if (isImplicitlyConvertible!(T, R))
199201
{
200-
return createRCWithContext(context, cast(R)context._get_value);
202+
import core.lifetime: move;
203+
return createRCWithContext(cast(R)context._get_value, move(context));
201204
}
202205

203206
/// ditto
204-
mir_rcptr!(const R) castTo(R, T)(return const mir_rcptr!T context) @trusted const
207+
mir_rcptr!(const R) castTo(R, T)(return const mir_rcptr!T context) @trusted
205208
if (isImplicitlyConvertible!(const T, const R))
206209
{
207-
return createRCWithContext(*cast(mir_rcptr!T*)&context, cast(const R)context._get_value);
210+
import core.lifetime: move;
211+
return createRCWithContext(cast(const R)context._get_value, move(*cast(mir_rcptr!T*)&context));
208212
}
209213

210214
/// ditto
211-
mir_rcptr!(immutable R) castTo(R, T)(return immutable mir_rcptr!T context) @trusted immutable
215+
mir_rcptr!(immutable R) castTo(R, T)(return immutable mir_rcptr!T context) @trusted
212216
if (isImplicitlyConvertible!(immutable T, immutable R))
213217
{
214-
return createRCWithContext(*cast(mir_rcptr!T*)&context, cast(immutable R)context._get_value);
218+
import core.lifetime: move;
219+
return createRCWithContext(cast(immutable R)context._get_value, move(*cast(mir_rcptr!T*)&context));
215220
}
216221

217222

@@ -302,7 +307,7 @@ unittest
302307

303308
version(unittest):
304309

305-
private struct _test_unpure_system_dest_s__ {
310+
package struct _test_unpure_system_dest_s__ {
306311
static int numStructs;
307312
int i;
308313

0 commit comments

Comments
 (0)