Skip to content

Commit 2ca716c

Browse files
Refactor variant
1 parent 72486ab commit 2ca716c

1 file changed

Lines changed: 97 additions & 32 deletions

File tree

source/nulib/data/variant.d

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import numem.core.exception;
1515
import numem.core.hooks;
1616
import numem.optional;
1717
import numem.lifetime;
18+
import numem.object;
1819

1920
/**
2021
A type which can contain any type in the language, stored on the heap.
@@ -27,26 +28,99 @@ import numem.lifetime;
2728
struct Variant {
2829
private:
2930
// Helpers that are not nogc, to allow usage with druntime.
30-
static bool isType(T)(TypeInfo id) => id == typeid(T);
31+
static bool isType(T)(TypeInfo id) {
32+
static if (is(T == class))
33+
auto selfTid = cast(TypeInfo_Class)typeid(T);
34+
else static if (is(T == interface))
35+
auto selfTid = cast(TypeInfo_Interface)typeid(T);
36+
else
37+
auto selfTid = typeid(T);
38+
39+
static if (is(T == class) || is(T == interface)) {
40+
if (auto tid = cast(TypeInfo_Class)typeid(T)) {
41+
return tid.isBaseOf(selfTid);
42+
}
43+
if (auto tid = cast(TypeInfo_Interface)typeid(T)) {
44+
return tid.isBaseOf(selfTid);
45+
}
46+
}
47+
return id == typeid(T);
48+
}
3149
static string getTypeName(TypeInfo id) => id.toString();
50+
alias destroyFuncT = void function(void* data) @nogc;
3251

3352
@nogc:
53+
3454
TypeInfo id;
55+
destroyFuncT destroyFunc;
3556
void* data;
3657

3758
// Internal ctor
38-
this(TypeInfo id, void* data) @trusted nothrow {
59+
this(TypeInfo id, void* data, void function(void* data) @nogc destroyFunc) @trusted nothrow {
3960
this.id = id;
61+
this.destroyFunc = destroyFunc;
4062
this.data = data;
4163
}
4264

65+
/// Helper that frees values.
66+
pragma(inline, true)
67+
void freeValue() @trusted nothrow {
68+
if (destroyFunc && data !is null)
69+
assumeNoThrowNoGC(destroyFunc, data);
70+
71+
this.id = null;
72+
this.destroyFunc = null;
73+
this.data = null;
74+
}
75+
76+
/// Helper that sets values.
77+
pragma(inline, true)
78+
void setValue(T)(auto ref T value) @trusted nothrow {
79+
static if (is(T == Variant)) {
80+
this.id = value.id;
81+
this.destroyFunc = value.destroyFunc;
82+
this.data = value.data;
83+
} else {
84+
this.id = typeid(T);
85+
86+
static if (isArray!T) {
87+
this.destroyFunc = (void* value) {
88+
T tmp = *cast(T*)value;
89+
nogc_trydelete(tmp[0..$]);
90+
nu_free(value);
91+
};
92+
} else static if (hasAnyDestructor!T) {
93+
this.destroyFunc = (void* value) {
94+
static if (isHeapAllocated!T)
95+
T* tmp = cast(T*)&value;
96+
else
97+
T* tmp = cast(T*)value;
98+
99+
nogc_trydelete(*tmp);
100+
};
101+
} else {
102+
this.destroyFunc = (void* value) {
103+
nu_free(value);
104+
};
105+
}
106+
107+
static if (isHeapAllocated!T) {
108+
this.data = cast(void*)value;
109+
} else {
110+
111+
this.data = nu_malloc(T.sizeof);
112+
*(cast(T*)this.data) = value.move();
113+
}
114+
}
115+
}
116+
43117
public:
44118
alias isInitialized this;
45119

46120
/**
47121
An empty variant.
48122
*/
49-
enum empty = Variant(null, null);
123+
enum empty = Variant(null, null, null);
50124

51125
/**
52126
Whether the variant is empty.
@@ -58,22 +132,16 @@ public:
58132
*/
59133
@property bool isInitialized() @trusted nothrow pure => id !is null && data !is null;
60134

135+
/**
136+
The type of the value stored in the variant.
137+
*/
138+
@property TypeInfo type() @trusted nothrow pure => id;
139+
61140
/**
62141
Constructor
63142
*/
64143
this(T)(auto ref T value) @trusted nothrow {
65-
static if (is(T == Variant)) {
66-
this.id = value.id;
67-
this.data = value.data;
68-
} else {
69-
this.id = typeid(T);
70-
static if (isHeapAllocated!T)
71-
this.data = cast(void*)value;
72-
else {
73-
this.data = nu_malloc(T.sizeof);
74-
*(cast(T*)this.data) = value.move();
75-
}
76-
}
144+
this.setValue!T(value);
77145
}
78146

79147
/**
@@ -125,18 +193,7 @@ public:
125193

126194
/// Allows assigning the variant to a value.
127195
void opAssign(T)(auto ref T value) @trusted nothrow {
128-
static if (is(T == Variant)) {
129-
this.id = value.id;
130-
this.data = value.data;
131-
} else {
132-
this.id = typeid(T);
133-
static if (isHeapAllocated!T)
134-
this.data = cast(void*)value;
135-
else {
136-
this.data = nu_malloc(T.sizeof);
137-
*(cast(T*)this.data) = value.move();
138-
}
139-
}
196+
this.setValue!T(value);
140197
}
141198

142199
/**
@@ -154,11 +211,7 @@ public:
154211
question.
155212
*/
156213
void free() @trusted nothrow {
157-
this.id = null;
158-
if (data) {
159-
nu_free(data);
160-
this.data = null;
161-
}
214+
this.freeValue();
162215
}
163216
}
164217

@@ -189,6 +242,18 @@ unittest {
189242
assert(v == v2 && !v);
190243
}
191244

245+
@("Variant: classes")
246+
unittest {
247+
static bool destroyed__ = false;
248+
static class TestClass { ~this() { destroyed__ = true; } uint t = 0; }
249+
250+
Variant obj = nogc_new!TestClass();
251+
assert(obj.get!Object());
252+
253+
obj.free();
254+
assert(destroyed__);
255+
}
256+
192257
@("Variant: arrays")
193258
unittest {
194259
Variant v = [0, 1, 2, 3].nu_dup();

0 commit comments

Comments
 (0)