| 1 |
// Written in the D programming language. |
|---|
| 2 |
|
|---|
| 3 |
/** |
|---|
| 4 |
This module implements a variety of type constructors, i.e., templates |
|---|
| 5 |
that allow construction of new, useful general-purpose types. |
|---|
| 6 |
|
|---|
| 7 |
Macros: |
|---|
| 8 |
|
|---|
| 9 |
WIKI = Phobos/StdVariant |
|---|
| 10 |
|
|---|
| 11 |
Synopsis: |
|---|
| 12 |
|
|---|
| 13 |
---- |
|---|
| 14 |
// value tuples |
|---|
| 15 |
alias Tuple!(float, "x", float, "y", float, "z") Coord; |
|---|
| 16 |
Coord c; |
|---|
| 17 |
c[1] = 1; // access by index |
|---|
| 18 |
c.z = 1; // access by given name |
|---|
| 19 |
alias Tuple!(string, string) DicEntry; // names can be omitted |
|---|
| 20 |
|
|---|
| 21 |
// Rebindable references to const and immutable objects |
|---|
| 22 |
void bar() |
|---|
| 23 |
{ |
|---|
| 24 |
const w1 = new Widget, w2 = new Widget; |
|---|
| 25 |
w1.foo(); |
|---|
| 26 |
// w1 = w2 would not work; can't rebind const object |
|---|
| 27 |
auto r = Rebindable!(const Widget)(w1); |
|---|
| 28 |
// invoke method as if r were a Widget object |
|---|
| 29 |
r.foo(); |
|---|
| 30 |
// rebind r to refer to another object |
|---|
| 31 |
r = w2; |
|---|
| 32 |
} |
|---|
| 33 |
---- |
|---|
| 34 |
|
|---|
| 35 |
Copyright: Copyright the respective authors, 2008- |
|---|
| 36 |
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). |
|---|
| 37 |
Authors: $(WEB erdani.org, Andrei Alexandrescu), |
|---|
| 38 |
$(WEB bartoszmilewski.wordpress.com, Bartosz Milewski), |
|---|
| 39 |
Don Clugston, |
|---|
| 40 |
Shin Fujishiro |
|---|
| 41 |
*/ |
|---|
| 42 |
module std.typecons; |
|---|
| 43 |
import core.memory, core.stdc.stdlib; |
|---|
| 44 |
import std.algorithm, std.array, std.conv, std.exception, std.format, |
|---|
| 45 |
std.metastrings, std.stdio, std.traits, std.typetuple, std.range; |
|---|
| 46 |
|
|---|
| 47 |
version(unittest) import core.vararg; |
|---|
| 48 |
|
|---|
| 49 |
/** |
|---|
| 50 |
Encapsulates unique ownership of a resource. Resource of type T is |
|---|
| 51 |
deleted at the end of the scope, unless it is transferred. The |
|---|
| 52 |
transfer can be explicit, by calling $(D release), or implicit, when |
|---|
| 53 |
returning Unique from a function. The resource can be a polymorphic |
|---|
| 54 |
class object, in which case Unique behaves polymorphically too. |
|---|
| 55 |
|
|---|
| 56 |
Example: |
|---|
| 57 |
*/ |
|---|
| 58 |
|
|---|
| 59 |
struct Unique(T) |
|---|
| 60 |
{ |
|---|
| 61 |
static if (is(T:Object)) |
|---|
| 62 |
alias T RefT; |
|---|
| 63 |
else |
|---|
| 64 |
alias T * RefT; |
|---|
| 65 |
public: |
|---|
| 66 |
/+ Doesn't work yet |
|---|
| 67 |
/** |
|---|
| 68 |
The safe constructor. It creates the resource and |
|---|
| 69 |
guarantees unique ownership of it (unless the constructor |
|---|
| 70 |
of $(D T) publishes aliases of $(D this)), |
|---|
| 71 |
*/ |
|---|
| 72 |
this(A...)(A args) |
|---|
| 73 |
{ |
|---|
| 74 |
_p = new T(args); |
|---|
| 75 |
} |
|---|
| 76 |
+/ |
|---|
| 77 |
|
|---|
| 78 |
/** |
|---|
| 79 |
Constructor that takes an rvalue. |
|---|
| 80 |
It will ensure uniqueness, as long as the rvalue |
|---|
| 81 |
isn't just a view on an lvalue (e.g., a cast) |
|---|
| 82 |
Typical usage: |
|---|
| 83 |
---- |
|---|
| 84 |
Unique!(Foo) f = new Foo; |
|---|
| 85 |
---- |
|---|
| 86 |
*/ |
|---|
| 87 |
this(RefT p) |
|---|
| 88 |
{ |
|---|
| 89 |
writeln("Unique constructor with rvalue"); |
|---|
| 90 |
_p = p; |
|---|
| 91 |
} |
|---|
| 92 |
/** |
|---|
| 93 |
Constructor that takes an lvalue. It nulls its source. |
|---|
| 94 |
The nulling will ensure uniqueness as long as there |
|---|
| 95 |
are no previous aliases to the source. |
|---|
| 96 |
*/ |
|---|
| 97 |
this(ref RefT p) |
|---|
| 98 |
{ |
|---|
| 99 |
_p = p; |
|---|
| 100 |
writeln("Unique constructor nulling source"); |
|---|
| 101 |
p = null; |
|---|
| 102 |
assert(p is null); |
|---|
| 103 |
} |
|---|
| 104 |
/+ Doesn't work yet |
|---|
| 105 |
/** |
|---|
| 106 |
Constructor that takes a Unique of a type that is convertible to our type: |
|---|
| 107 |
Disallow construction from lvalue (force the use of release on the source Unique) |
|---|
| 108 |
If the source is an rvalue, null its content, so the destrutctor doesn't delete it |
|---|
| 109 |
|
|---|
| 110 |
Typically used by the compiler to return $(D Unique) of derived type as $(D Unique) |
|---|
| 111 |
of base type. |
|---|
| 112 |
|
|---|
| 113 |
Example: |
|---|
| 114 |
---- |
|---|
| 115 |
Unique!(Base) create() |
|---|
| 116 |
{ |
|---|
| 117 |
Unique!(Derived) d = new Derived; |
|---|
| 118 |
return d; // Implicit Derived->Base conversion |
|---|
| 119 |
} |
|---|
| 120 |
---- |
|---|
| 121 |
*/ |
|---|
| 122 |
this(U)(ref Unique!(U) u) = null; |
|---|
| 123 |
this(U)(Unique!(U) u) |
|---|
| 124 |
{ |
|---|
| 125 |
_p = u._p; |
|---|
| 126 |
u._p = null; |
|---|
| 127 |
} |
|---|
| 128 |
+/ |
|---|
| 129 |
|
|---|
| 130 |
~this() |
|---|
| 131 |
{ |
|---|
| 132 |
writeln("Unique destructor of ", (_p is null)? null: _p); |
|---|
| 133 |
delete _p; |
|---|
| 134 |
_p = null; |
|---|
| 135 |
} |
|---|
| 136 |
bool isEmpty() const |
|---|
| 137 |
{ |
|---|
| 138 |
return _p is null; |
|---|
| 139 |
} |
|---|
| 140 |
/** Returns a unique rvalue. Nullifies the current contents */ |
|---|
| 141 |
Unique release() |
|---|
| 142 |
{ |
|---|
| 143 |
writeln("Release"); |
|---|
| 144 |
auto u = Unique(_p); |
|---|
| 145 |
assert(_p is null); |
|---|
| 146 |
writeln("return from Release"); |
|---|
| 147 |
return u; |
|---|
| 148 |
} |
|---|
| 149 |
/** Forwards member access to contents */ |
|---|
| 150 |
RefT opDot() { return _p; } |
|---|
| 151 |
|
|---|
| 152 |
/+ doesn't work yet! |
|---|
| 153 |
/** |
|---|
| 154 |
Postblit operator is undefined to prevent the cloning of $(D Unique) objects |
|---|
| 155 |
*/ |
|---|
| 156 |
this(this) = null; |
|---|
| 157 |
+/ |
|---|
| 158 |
|
|---|
| 159 |
private: |
|---|
| 160 |
RefT _p; |
|---|
| 161 |
} |
|---|
| 162 |
|
|---|
| 163 |
/+ doesn't work yet |
|---|
| 164 |
unittest |
|---|
| 165 |
{ |
|---|
| 166 |
writeln("Unique class"); |
|---|
| 167 |
class Bar |
|---|
| 168 |
{ |
|---|
| 169 |
~this() { writefln(" Bar destructor"); } |
|---|
| 170 |
int val() const { return 4; } |
|---|
| 171 |
} |
|---|
| 172 |
alias Unique!(Bar) UBar; |
|---|
| 173 |
UBar g(UBar u) |
|---|
| 174 |
{ |
|---|
| 175 |
return u; |
|---|
| 176 |
} |
|---|
| 177 |
auto ub = UBar(new Bar); |
|---|
| 178 |
assert(!ub.isEmpty); |
|---|
| 179 |
assert(ub.val == 4); |
|---|
| 180 |
// should not compile |
|---|
| 181 |
// auto ub3 = g(ub); |
|---|
| 182 |
writeln("Calling g"); |
|---|
| 183 |
auto ub2 = g(ub.release); |
|---|
| 184 |
assert(ub.isEmpty); |
|---|
| 185 |
assert(!ub2.isEmpty); |
|---|
| 186 |
} |
|---|
| 187 |
|
|---|
| 188 |
unittest |
|---|
| 189 |
{ |
|---|
| 190 |
writeln("Unique struct"); |
|---|
| 191 |
struct Foo |
|---|
| 192 |
{ |
|---|
| 193 |
~this() { writefln(" Bar destructor"); } |
|---|
| 194 |
int val() const { return 3; } |
|---|
| 195 |
} |
|---|
| 196 |
alias Unique!(Foo) UFoo; |
|---|
| 197 |
|
|---|
| 198 |
UFoo f(UFoo u) |
|---|
| 199 |
{ |
|---|
| 200 |
writeln("inside f"); |
|---|
| 201 |
return u; |
|---|
| 202 |
} |
|---|
| 203 |
|
|---|
| 204 |
auto uf = UFoo(new Foo); |
|---|
| 205 |
assert(!uf.isEmpty); |
|---|
| 206 |
assert(uf.val == 3); |
|---|
| 207 |
// should not compile |
|---|
| 208 |
// auto uf3 = f(uf); |
|---|
| 209 |
writeln("Unique struct: calling f"); |
|---|
| 210 |
auto uf2 = f(uf.release); |
|---|
| 211 |
assert(uf.isEmpty); |
|---|
| 212 |
assert(!uf2.isEmpty); |
|---|
| 213 |
} |
|---|
| 214 |
+/ |
|---|
| 215 |
|
|---|
| 216 |
|
|---|
| 217 |
/** |
|---|
| 218 |
Tuple of values, for example $(D Tuple!(int, string)) is a record that |
|---|
| 219 |
stores an $(D int) and a $(D string). $(D Tuple) can be used to bundle |
|---|
| 220 |
values together, notably when returning multiple values from a |
|---|
| 221 |
function. If $(D obj) is a tuple, the individual members are |
|---|
| 222 |
accessible with the syntax $(D obj[0]) for the first field, $(D obj[1]) |
|---|
| 223 |
for the second, and so on. |
|---|
| 224 |
|
|---|
| 225 |
The choice of zero-based indexing instead of one-base indexing was |
|---|
| 226 |
motivated by the ability to use value tuples with various compile-time |
|---|
| 227 |
loop constructs (e.g. type tuple iteration), all of which use |
|---|
| 228 |
zero-based indexing. |
|---|
| 229 |
|
|---|
| 230 |
Example: |
|---|
| 231 |
|
|---|
| 232 |
---- |
|---|
| 233 |
Tuple!(int, int) point; |
|---|
| 234 |
// assign coordinates |
|---|
| 235 |
point[0] = 5; |
|---|
| 236 |
point[1] = 6; |
|---|
| 237 |
// read coordinates |
|---|
| 238 |
auto x = point[0]; |
|---|
| 239 |
auto y = point[1]; |
|---|
| 240 |
---- |
|---|
| 241 |
|
|---|
| 242 |
Tuple members can be named. It is legal to mix named and unnamed |
|---|
| 243 |
members. The method above is still applicable to all fields. |
|---|
| 244 |
|
|---|
| 245 |
Example: |
|---|
| 246 |
|
|---|
| 247 |
---- |
|---|
| 248 |
alias Tuple!(int, "index", string, "value") Entry; |
|---|
| 249 |
Entry e; |
|---|
| 250 |
e.index = 4; |
|---|
| 251 |
e.value = "Hello"; |
|---|
| 252 |
assert(e[1] == "Hello"); |
|---|
| 253 |
assert(e[0] == 4); |
|---|
| 254 |
---- |
|---|
| 255 |
|
|---|
| 256 |
Tuples with named fields are distinct types from tuples with unnamed |
|---|
| 257 |
fields, i.e. each naming imparts a separate type for the tuple. Two |
|---|
| 258 |
tuple differing in naming only are still distinct, even though they |
|---|
| 259 |
might have the same structure. |
|---|
| 260 |
|
|---|
| 261 |
Example: |
|---|
| 262 |
|
|---|
| 263 |
---- |
|---|
| 264 |
Tuple!(int, "x", int, "y") point1; |
|---|
| 265 |
Tuple!(int, int) point2; |
|---|
| 266 |
assert(!is(typeof(point1) == typeof(point2))); // passes |
|---|
| 267 |
---- |
|---|
| 268 |
*/ |
|---|
| 269 |
struct Tuple(Specs...) |
|---|
| 270 |
{ |
|---|
| 271 |
private: |
|---|
| 272 |
|
|---|
| 273 |
// Parse (type,name) pairs (FieldSpecs) out of the specified |
|---|
| 274 |
// arguments. Some fields would have name, others not. |
|---|
| 275 |
template parseSpecs(Specs...) |
|---|
| 276 |
{ |
|---|
| 277 |
static if (Specs.length == 0) |
|---|
| 278 |
{ |
|---|
| 279 |
alias TypeTuple!() parseSpecs; |
|---|
| 280 |
} |
|---|
| 281 |
else static if (is(Specs[0])) |
|---|
| 282 |
{ |
|---|
| 283 |
static if (is(typeof(Specs[1]) : string)) |
|---|
| 284 |
{ |
|---|
| 285 |
alias TypeTuple!(FieldSpec!(Specs[0 .. 2]), |
|---|
| 286 |
parseSpecs!(Specs[2 .. $])) parseSpecs; |
|---|
| 287 |
} |
|---|
| 288 |
else |
|---|
| 289 |
{ |
|---|
| 290 |
alias TypeTuple!(FieldSpec!(Specs[0]), |
|---|
| 291 |
parseSpecs!(Specs[1 .. $])) parseSpecs; |
|---|
| 292 |
} |
|---|
| 293 |
} |
|---|
| 294 |
else |
|---|
| 295 |
{ |
|---|
| 296 |
static assert(0, "Attempted to instantiate Tuple with an " |
|---|
| 297 |
~"invalid argument: "~ Specs[0].stringof); |
|---|
| 298 |
} |
|---|
| 299 |
} |
|---|
| 300 |
|
|---|
| 301 |
template FieldSpec(T, string s = "") |
|---|
| 302 |
{ |
|---|
| 303 |
alias T Type; |
|---|
| 304 |
alias s name; |
|---|
| 305 |
} |
|---|
| 306 |
|
|---|
| 307 |
alias parseSpecs!Specs fieldSpecs; |
|---|
| 308 |
|
|---|
| 309 |
// Used with staticMap. |
|---|
| 310 |
template extractType(alias spec) { alias spec.Type extractType; } |
|---|
| 311 |
template extractName(alias spec) { alias spec.name extractName; } |
|---|
| 312 |
|
|---|
| 313 |
// Generates named fields as follows: |
|---|
| 314 |
// alias Identity!(field[0]) name_0; |
|---|
| 315 |
// alias Identity!(field[1]) name_1; |
|---|
| 316 |
// : |
|---|
| 317 |
// NOTE: field[k] is an expression (which yields a symbol of a |
|---|
| 318 |
// variable) and can't be aliased directly. |
|---|
| 319 |
static string injectNamedFields() |
|---|
| 320 |
{ |
|---|
| 321 |
string decl = ""; |
|---|
| 322 |
foreach (i, name; staticMap!(extractName, fieldSpecs)) |
|---|
| 323 |
{ |
|---|
| 324 |
auto field = text("Identity!(field[", i, "])"); |
|---|
| 325 |
auto numbered = text("_", i); |
|---|
| 326 |
decl ~= text("alias ", field, " ", numbered, ";"); |
|---|
| 327 |
if (name.length != 0) |
|---|
| 328 |
{ |
|---|
| 329 |
decl ~= text("alias ", numbered, " ", name, ";"); |
|---|
| 330 |
} |
|---|
| 331 |
} |
|---|
| 332 |
return decl; |
|---|
| 333 |
} |
|---|
| 334 |
|
|---|
| 335 |
// Returns Specs for a subtuple this[from .. to] preserving field |
|---|
| 336 |
// names if any. |
|---|
| 337 |
template sliceSpecs(size_t from, size_t to) |
|---|
| 338 |
{ |
|---|
| 339 |
alias staticMap!(expandSpec, |
|---|
| 340 |
fieldSpecs[from .. to]) sliceSpecs; |
|---|
| 341 |
} |
|---|
| 342 |
|
|---|
| 343 |
template expandSpec(alias spec) |
|---|
| 344 |
{ |
|---|
| 345 |
static if (spec.name.length == 0) |
|---|
| 346 |
{ |
|---|
| 347 |
alias TypeTuple!(spec.Type) expandSpec; |
|---|
| 348 |
} |
|---|
| 349 |
else |
|---|
| 350 |
{ |
|---|
| 351 |
alias TypeTuple!(spec.Type, spec.name) expandSpec; |
|---|
| 352 |
} |
|---|
| 353 |
} |
|---|
| 354 |
|
|---|
| 355 |
public: |
|---|
| 356 |
/** |
|---|
| 357 |
The type of the tuple's components. |
|---|
| 358 |
*/ |
|---|
| 359 |
alias staticMap!(extractType, fieldSpecs) Types; |
|---|
| 360 |
|
|---|
| 361 |
Types field; |
|---|
| 362 |
mixin(injectNamedFields()); |
|---|
| 363 |
alias field expand; |
|---|
| 364 |
alias field this; |
|---|
| 365 |
|
|---|
| 366 |
// This mitigates breakage of old code now that std.range.Zip uses |
|---|
| 367 |
// Tuple instead of the old Proxy. It's intentionally lacking ddoc |
|---|
| 368 |
// because it should eventually be deprecated. |
|---|
| 369 |
auto at(size_t index)() { |
|---|
| 370 |
return field[index]; |
|---|
| 371 |
} |
|---|
| 372 |
|
|---|
| 373 |
/** |
|---|
| 374 |
Constructor taking one value for each field. Each argument must be |
|---|
| 375 |
implicitly assignable to the respective element of the target. |
|---|
| 376 |
*/ |
|---|
| 377 |
this(U...)(U values) if (U.length == Types.length) |
|---|
| 378 |
{ |
|---|
| 379 |
foreach (i, Unused; Types) |
|---|
| 380 |
{ |
|---|
| 381 |
field[i] = values[i]; |
|---|
| 382 |
} |
|---|
| 383 |
} |
|---|
| 384 |
|
|---|
| 385 |
/** |
|---|
| 386 |
Constructor taking a compatible tuple. Each element of the source |
|---|
| 387 |
must be implicitly assignable to the respective element of the |
|---|
| 388 |
target. |
|---|
| 389 |
*/ |
|---|
| 390 |
this(U)(U another) if (isTuple!U) |
|---|
| 391 |
{ |
|---|
| 392 |
static assert(field.length == another.field.length, |
|---|
| 393 |
"Length mismatch in attempting to construct a " |
|---|
| 394 |
~ typeof(this).stringof ~" with a "~ U.stringof); |
|---|
| 395 |
foreach (i, T; Types) |
|---|
| 396 |
{ |
|---|
| 397 |
field[i] = another.field[i]; |
|---|
| 398 |
} |
|---|
| 399 |
} |
|---|
| 400 |
|
|---|
| 401 |
/** |
|---|
| 402 |
Comparison for equality. |
|---|
| 403 |
*/ |
|---|
| 404 |
bool opEquals(R)(R rhs) if (isTuple!R) |
|---|
| 405 |
{ |
|---|
| 406 |
static assert(field.length == rhs.field.length, |
|---|
| 407 |
"Length mismatch in attempting to compare a " |
|---|
| 408 |
~typeof(this).stringof |
|---|
| 409 |
~" with a "~typeof(rhs).stringof); |
|---|
| 410 |
foreach (i, Unused; Types) |
|---|
| 411 |
{ |
|---|
| 412 |
if (field[i] != rhs.field[i]) return false; |
|---|
| 413 |
} |
|---|
| 414 |
return true; |
|---|
| 415 |
} |
|---|
| 416 |
|
|---|
| 417 |
/** |
|---|
| 418 |
Comparison for ordering. |
|---|
| 419 |
*/ |
|---|
| 420 |
int opCmp(R)(R rhs) if (isTuple!R) |
|---|
| 421 |
{ |
|---|
| 422 |
static assert(field.length == rhs.field.length, |
|---|
| 423 |
"Length mismatch in attempting to compare a " |
|---|
| 424 |
~typeof(this).stringof |
|---|
| 425 |
~" with a "~typeof(rhs).stringof); |
|---|
| 426 |
foreach (i, Unused; Types) |
|---|
| 427 |
{ |
|---|
| 428 |
if (field[i] != rhs.field[i]) |
|---|
| 429 |
{ |
|---|
| 430 |
return field[i] < rhs.field[i] ? -1 : 1; |
|---|
| 431 |
} |
|---|
| 432 |
} |
|---|
| 433 |
return 0; |
|---|
| 434 |
} |
|---|
| 435 |
|
|---|
| 436 |
/** |
|---|
| 437 |
Assignment from another tuple. Each element of the source must be |
|---|
| 438 |
implicitly assignable to the respective element of the target. |
|---|
| 439 |
*/ |
|---|
| 440 |
void opAssign(R)(R rhs) if (isTuple!R) |
|---|
| 441 |
{ |
|---|
| 442 |
static assert(field.length == rhs.field.length, |
|---|
| 443 |
"Length mismatch in attempting to assign a " |
|---|
| 444 |
~ R.stringof ~" to a "~ typeof(this).stringof); |
|---|
| 445 |
// Do not swap; opAssign should be called on the fields. |
|---|
| 446 |
foreach (i, Unused; Types) |
|---|
| 447 |
{ |
|---|
| 448 |
field[i] = rhs.field[i]; |
|---|
| 449 |
} |
|---|
| 450 |
} |
|---|
| 451 |
|
|---|
| 452 |
deprecated void assign(R)(R rhs) if (isTuple!R) |
|---|
| 453 |
{ |
|---|
| 454 |
this = rhs; |
|---|
| 455 |
} |
|---|
| 456 |
|
|---|
| 457 |
// @@@BUG4424@@@ workaround |
|---|
| 458 |
private mixin template _workaround4424() |
|---|
| 459 |
{ |
|---|
| 460 |
@disable void opAssign(typeof(this) ); |
|---|
| 461 |
} |
|---|
| 462 |
mixin _workaround4424; |
|---|
| 463 |
|
|---|
| 464 |
/** |
|---|
| 465 |
Takes a slice of the tuple. |
|---|
| 466 |
|
|---|
| 467 |
Example: |
|---|
| 468 |
|
|---|
| 469 |
---- |
|---|
| 470 |
Tuple!(int, string, float, double) a; |
|---|
| 471 |
a[1] = "abc"; |
|---|
| 472 |
a[2] = 4.5; |
|---|
| 473 |
auto s = a.slice!(1, 3); |
|---|
| 474 |
static assert(is(typeof(s) == Tuple!(string, float))); |
|---|
| 475 |
assert(s[0] == "abc" && s[1] == 4.5); |
|---|
| 476 |
---- |
|---|
| 477 |
*/ |
|---|
| 478 |
@property |
|---|
| 479 |
ref Tuple!(sliceSpecs!(from, to)) slice(uint from, uint to)() |
|---|
| 480 |
{ |
|---|
| 481 |
return *cast(typeof(return) *) &(field[from]); |
|---|
| 482 |
} |
|---|
| 483 |
|
|---|
| 484 |
/** |
|---|
| 485 |
The length of the tuple. |
|---|
| 486 |
*/ |
|---|
| 487 |
enum length = field.length; |
|---|
| 488 |
|
|---|
| 489 |
/** |
|---|
| 490 |
Converts to string. |
|---|
| 491 |
*/ |
|---|
| 492 |
string toString() |
|---|
| 493 |
{ |
|---|
| 494 |
enum header = typeof(this).stringof ~ "(", |
|---|
| 495 |
footer = ")", |
|---|
| 496 |
separator = ", "; |
|---|
| 497 |
Appender!string app; |
|---|
| 498 |
app.put(header); |
|---|
| 499 |
foreach (i, Unused; Types) |
|---|
| 500 |
{ |
|---|
| 501 |
static if (i > 0) |
|---|
| 502 |
{ |
|---|
| 503 |
app.put(separator); |
|---|
| 504 |
} |
|---|
| 505 |
// TODO: Change this once toString() works for shared objects. |
|---|
| 506 |
static if (is(Unused == class) && is(Unused == shared)) |
|---|
| 507 |
formattedWrite(app, "%s", field[i].stringof); |
|---|
| 508 |
else |
|---|
| 509 |
formattedWrite(app, "%s", field[i]); |
|---|
| 510 |
} |
|---|
| 511 |
app.put(footer); |
|---|
| 512 |
return app.data; |
|---|
| 513 |
} |
|---|
| 514 |
} |
|---|
| 515 |
|
|---|
| 516 |
private template Identity(alias T) |
|---|
| 517 |
{ |
|---|
| 518 |
alias T Identity; |
|---|
| 519 |
} |
|---|
| 520 |
|
|---|
| 521 |
unittest |
|---|
| 522 |
{ |
|---|
| 523 |
{ |
|---|
| 524 |
Tuple!(int, "a", int, "b") nosh; |
|---|
| 525 |
static assert(nosh.length == 2); |
|---|
| 526 |
nosh.a = 5; |
|---|
| 527 |
nosh.b = 6; |
|---|
| 528 |
assert(nosh.a == 5); |
|---|
| 529 |
assert(nosh.b == 6); |
|---|
| 530 |
} |
|---|
| 531 |
{ |
|---|
| 532 |
Tuple!(short, double) b; |
|---|
| 533 |
static assert(b.length == 2); |
|---|
| 534 |
b[1] = 5; |
|---|
| 535 |
auto a = Tuple!(int, real)(b); |
|---|
| 536 |
assert(a[0] == 0 && a[1] == 5); |
|---|
| 537 |
a = Tuple!(int, real)(1, 2); |
|---|
| 538 |
assert(a[0] == 1 && a[1] == 2); |
|---|
| 539 |
auto c = Tuple!(int, "a", double, "b")(a); |
|---|
| 540 |
assert(c[0] == 1 && c[1] == 2); |
|---|
| 541 |
} |
|---|
| 542 |
{ |
|---|
| 543 |
Tuple!(int, real) nosh; |
|---|
| 544 |
nosh[0] = 5; |
|---|
| 545 |
nosh[1] = 0; |
|---|
| 546 |
assert(nosh[0] == 5 && nosh[1] == 0); |
|---|
| 547 |
assert(nosh.toString == "Tuple!(int,real)(5, 0)", nosh.toString); |
|---|
| 548 |
Tuple!(int, int) yessh; |
|---|
| 549 |
nosh = yessh; |
|---|
| 550 |
} |
|---|
| 551 |
{ |
|---|
| 552 |
Tuple!(int, "a", double, "b") x; |
|---|
| 553 |
static assert(x.a.offsetof == x[0].offsetof); |
|---|
| 554 |
static assert(x.b.offsetof == x[1].offsetof); |
|---|
| 555 |
x.b = 4.5; |
|---|
| 556 |
x.a = 5; |
|---|
| 557 |
assert(x[0] == 5 && x[1] == 4.5); |
|---|
| 558 |
assert(x.a == 5 && x.b == 4.5); |
|---|
| 559 |
} |
|---|
| 560 |
// indexing |
|---|
| 561 |
{ |
|---|
| 562 |
Tuple!(int, real) t; |
|---|
| 563 |
static assert(is(typeof(t[0]) == int)); |
|---|
| 564 |
static assert(is(typeof(t[1]) == real)); |
|---|
| 565 |
int* p0 = &t[0]; |
|---|
| 566 |
real* p1 = &t[1]; |
|---|
| 567 |
t[0] = 10; |
|---|
| 568 |
t[1] = -200.0L; |
|---|
| 569 |
assert(*p0 == t[0]); |
|---|
| 570 |
assert(*p1 == t[1]); |
|---|
| 571 |
} |
|---|
| 572 |
// slicing |
|---|
| 573 |
{ |
|---|
| 574 |
Tuple!(int, "x", real, "y", double, "z", string) t; |
|---|
| 575 |
t[0] = 10; |
|---|
| 576 |
t[1] = 11; |
|---|
| 577 |
t[2] = 12; |
|---|
| 578 |
t[3] = "abc"; |
|---|
| 579 |
auto a = t.slice!(0, 3); |
|---|
| 580 |
assert(a.length == 3); |
|---|
| 581 |
assert(a.x == t.x); |
|---|
| 582 |
assert(a.y == t.y); |
|---|
| 583 |
assert(a.z == t.z); |
|---|
| 584 |
auto b = t.slice!(2, 4); |
|---|
| 585 |
assert(b.length == 2); |
|---|
| 586 |
assert(b.z == t.z); |
|---|
| 587 |
assert(b[1] == t[3]); |
|---|
| 588 |
} |
|---|
| 589 |
// nesting |
|---|
| 590 |
{ |
|---|
| 591 |
Tuple!(Tuple!(int, real), Tuple!(string, "s")) t; |
|---|
| 592 |
static assert(is(typeof(t[0]) == Tuple!(int, real))); |
|---|
| 593 |
static assert(is(typeof(t[1]) == Tuple!(string, "s"))); |
|---|
| 594 |
static assert(is(typeof(t[0][0]) == int)); |
|---|
| 595 |
static assert(is(typeof(t[0][1]) == real)); |
|---|
| 596 |
static assert(is(typeof(t[1].s) == string)); |
|---|
| 597 |
t[0] = tuple(10, 20.0L); |
|---|
| 598 |
t[1].s = "abc"; |
|---|
| 599 |
assert(t[0][0] == 10); |
|---|
| 600 |
assert(t[0][1] == 20.0L); |
|---|
| 601 |
assert(t[1].s == "abc"); |
|---|
| 602 |
} |
|---|
| 603 |
// non-POD |
|---|
| 604 |
{ |
|---|
| 605 |
static struct S |
|---|
| 606 |
{ |
|---|
| 607 |
int count; |
|---|
| 608 |
this(this) { ++count; } |
|---|
| 609 |
~this() { --count; } |
|---|
| 610 |
void opAssign(S rhs) { count = rhs.count; } |
|---|
| 611 |
} |
|---|
| 612 |
Tuple!(S, S) ss; |
|---|
| 613 |
Tuple!(S, S) ssCopy = ss; |
|---|
| 614 |
assert(ssCopy[0].count == 1); |
|---|
| 615 |
assert(ssCopy[1].count == 1); |
|---|
| 616 |
ssCopy[1] = ssCopy[0]; |
|---|
| 617 |
assert(ssCopy[1].count == 2); |
|---|
| 618 |
} |
|---|
| 619 |
// bug 2800 |
|---|
| 620 |
{ |
|---|
| 621 |
static struct R |
|---|
| 622 |
{ |
|---|
| 623 |
Tuple!(int, int) _front; |
|---|
| 624 |
@property ref Tuple!(int, int) front() { return _front; } |
|---|
| 625 |
@property bool empty() { return _front[0] >= 10; } |
|---|
| 626 |
void popFront() { ++_front[0]; } |
|---|
| 627 |
} |
|---|
| 628 |
foreach (a; R()) |
|---|
| 629 |
{ |
|---|
| 630 |
static assert(is(typeof(a) == Tuple!(int, int))); |
|---|
| 631 |
assert(0 <= a[0] && a[0] < 10); |
|---|
| 632 |
assert(a[1] == 0); |
|---|
| 633 |
} |
|---|
| 634 |
} |
|---|
| 635 |
// Construction with compatible tuple |
|---|
| 636 |
{ |
|---|
| 637 |
Tuple!(int, int) x; |
|---|
| 638 |
x[0] = 10; |
|---|
| 639 |
x[1] = 20; |
|---|
| 640 |
Tuple!(int, "a", double, "b") y = x; |
|---|
| 641 |
assert(y.a == 10); |
|---|
| 642 |
assert(y.b == 20); |
|---|
| 643 |
// incompatible |
|---|
| 644 |
static assert(!__traits(compiles, Tuple!(int, int)(y))); |
|---|
| 645 |
} |
|---|
| 646 |
} |
|---|
| 647 |
|
|---|
| 648 |
/** |
|---|
| 649 |
Returns a $(D Tuple) object instantiated and initialized according to |
|---|
| 650 |
the arguments. |
|---|
| 651 |
|
|---|
| 652 |
Example: |
|---|
| 653 |
---- |
|---|
| 654 |
auto value = tuple(5, 6.7, "hello"); |
|---|
| 655 |
assert(value[0] == 5); |
|---|
| 656 |
assert(value[1] == 6.7); |
|---|
| 657 |
assert(value[2] == "hello"); |
|---|
| 658 |
---- |
|---|
| 659 |
*/ |
|---|
| 660 |
|
|---|
| 661 |
Tuple!(T) tuple(T...)(T args) |
|---|
| 662 |
{ |
|---|
| 663 |
typeof(return) result; |
|---|
| 664 |
static if (T.length > 0) result.field = args; |
|---|
| 665 |
return result; |
|---|
| 666 |
} |
|---|
| 667 |
|
|---|
| 668 |
/** |
|---|
| 669 |
Returns $(D true) if and only if $(D T) is an instance of the |
|---|
| 670 |
$(D Tuple) struct template. |
|---|
| 671 |
*/ |
|---|
| 672 |
template isTuple(T) |
|---|
| 673 |
{ |
|---|
| 674 |
static if (is(Unqual!T Unused : Tuple!Specs, Specs...)) |
|---|
| 675 |
{ |
|---|
| 676 |
enum isTuple = true; |
|---|
| 677 |
} |
|---|
| 678 |
else |
|---|
| 679 |
{ |
|---|
| 680 |
enum isTuple = false; |
|---|
| 681 |
} |
|---|
| 682 |
} |
|---|
| 683 |
|
|---|
| 684 |
unittest |
|---|
| 685 |
{ |
|---|
| 686 |
static assert(isTuple!(Tuple!())); |
|---|
| 687 |
static assert(isTuple!(Tuple!(int))); |
|---|
| 688 |
static assert(isTuple!(Tuple!(int, real, string))); |
|---|
| 689 |
static assert(isTuple!(Tuple!(int, "x", real, "y"))); |
|---|
| 690 |
static assert(isTuple!(Tuple!(int, Tuple!(real), string))); |
|---|
| 691 |
|
|---|
| 692 |
static assert(isTuple!(const Tuple!(int))); |
|---|
| 693 |
static assert(isTuple!(immutable Tuple!(int))); |
|---|
| 694 |
|
|---|
| 695 |
static assert(!isTuple!(int)); |
|---|
| 696 |
static assert(!isTuple!(const int)); |
|---|
| 697 |
|
|---|
| 698 |
struct S {} |
|---|
| 699 |
static assert(!isTuple!(S)); |
|---|
| 700 |
} |
|---|
| 701 |
|
|---|
| 702 |
|
|---|
| 703 |
private template enumValuesImpl(string name, BaseType, long index, T...) |
|---|
| 704 |
{ |
|---|
| 705 |
static if (name.length) |
|---|
| 706 |
{ |
|---|
| 707 |
enum string enumValuesImpl = "enum "~name~" : "~BaseType.stringof |
|---|
| 708 |
~" { "~enumValuesImpl!("", BaseType, index, T)~"}\n"; |
|---|
| 709 |
} |
|---|
| 710 |
else |
|---|
| 711 |
{ |
|---|
| 712 |
static if (!T.length) |
|---|
| 713 |
{ |
|---|
| 714 |
enum string enumValuesImpl = ""; |
|---|
| 715 |
} |
|---|
| 716 |
else |
|---|
| 717 |
{ |
|---|
| 718 |
static if (T.length == 1 |
|---|
| 719 |
|| T.length > 1 && is(typeof(T[1]) : string)) |
|---|
| 720 |
{ |
|---|
| 721 |
enum string enumValuesImpl = T[0]~" = "~ToString!(index)~", " |
|---|
| 722 |
~enumValuesImpl!("", BaseType, index + 1, T[1 .. $]); |
|---|
| 723 |
} |
|---|
| 724 |
else |
|---|
| 725 |
{ |
|---|
| 726 |
enum string enumValuesImpl = T[0]~" = "~ToString!(T[1])~", " |
|---|
| 727 |
~enumValuesImpl!("", BaseType, T[1] + 1, T[2 .. $]); |
|---|
| 728 |
} |
|---|
| 729 |
} |
|---|
| 730 |
} |
|---|
| 731 |
} |
|---|
| 732 |
|
|---|
| 733 |
private template enumParserImpl(string name, bool first, T...) |
|---|
| 734 |
{ |
|---|
| 735 |
static if (first) |
|---|
| 736 |
{ |
|---|
| 737 |
enum string enumParserImpl = "bool enumFromString(string s, ref " |
|---|
| 738 |
~name~" v) {\n" |
|---|
| 739 |
~enumParserImpl!(name, false, T) |
|---|
| 740 |
~"return false;\n}\n"; |
|---|
| 741 |
} |
|---|
| 742 |
else |
|---|
| 743 |
{ |
|---|
| 744 |
static if (T.length) |
|---|
| 745 |
enum string enumParserImpl = |
|---|
| 746 |
"if (s == `"~T[0]~"`) return (v = "~name~"."~T[0]~"), true;\n" |
|---|
| 747 |
~enumParserImpl!(name, false, T[1 .. $]); |
|---|
| 748 |
else |
|---|
| 749 |
enum string enumParserImpl = ""; |
|---|
| 750 |
} |
|---|
| 751 |
} |
|---|
| 752 |
|
|---|
| 753 |
private template enumPrinterImpl(string name, bool first, T...) |
|---|
| 754 |
{ |
|---|
| 755 |
static if (first) |
|---|
| 756 |
{ |
|---|
| 757 |
enum string enumPrinterImpl = "string enumToString("~name~" v) {\n" |
|---|
| 758 |
~enumPrinterImpl!(name, false, T)~"\n}\n"; |
|---|
| 759 |
} |
|---|
| 760 |
else |
|---|
| 761 |
{ |
|---|
| 762 |
static if (T.length) |
|---|
| 763 |
enum string enumPrinterImpl = |
|---|
| 764 |
"if (v == "~name~"."~T[0]~") return `"~T[0]~"`;\n" |
|---|
| 765 |
~enumPrinterImpl!(name, false, T[1 .. $]); |
|---|
| 766 |
else |
|---|
| 767 |
enum string enumPrinterImpl = "return null;"; |
|---|
| 768 |
} |
|---|
| 769 |
} |
|---|
| 770 |
|
|---|
| 771 |
private template ValueTuple(T...) |
|---|
| 772 |
{ |
|---|
| 773 |
alias T ValueTuple; |
|---|
| 774 |
} |
|---|
| 775 |
|
|---|
| 776 |
private template StringsOnly(T...) |
|---|
| 777 |
{ |
|---|
| 778 |
static if (T.length == 1) |
|---|
| 779 |
static if (is(typeof(T[0]) : string)) |
|---|
| 780 |
alias ValueTuple!(T[0]) StringsOnly; |
|---|
| 781 |
else |
|---|
| 782 |
alias ValueTuple!() StringsOnly; |
|---|
| 783 |
else |
|---|
| 784 |
static if (is(typeof(T[0]) : string)) |
|---|
| 785 |
alias ValueTuple!(T[0], StringsOnly!(T[1 .. $])) StringsOnly; |
|---|
| 786 |
else |
|---|
| 787 |
alias ValueTuple!(StringsOnly!(T[1 .. $])) StringsOnly; |
|---|
| 788 |
} |
|---|
| 789 |
|
|---|
| 790 |
/** |
|---|
| 791 |
Defines truly named enumerated values with parsing and stringizing |
|---|
| 792 |
primitives. |
|---|
| 793 |
|
|---|
| 794 |
Example: |
|---|
| 795 |
|
|---|
| 796 |
---- |
|---|
| 797 |
mixin(defineEnum!("Abc", "A", "B", 5, "C")); |
|---|
| 798 |
---- |
|---|
| 799 |
|
|---|
| 800 |
is equivalent to the following code: |
|---|
| 801 |
|
|---|
| 802 |
---- |
|---|
| 803 |
enum Abc { A, B = 5, C } |
|---|
| 804 |
string enumToString(Abc v) { ... } |
|---|
| 805 |
Abc enumFromString(string s) { ... } |
|---|
| 806 |
---- |
|---|
| 807 |
|
|---|
| 808 |
The $(D enumToString) function generates the unqualified names |
|---|
| 809 |
of the enumerated values, i.e. "A", "B", and "C". The $(D |
|---|
| 810 |
enumFromString) function expects one of "A", "B", and "C", and throws |
|---|
| 811 |
an exception in any other case. |
|---|
| 812 |
|
|---|
| 813 |
A base type can be specified for the enumeration like this: |
|---|
| 814 |
|
|---|
| 815 |
---- |
|---|
| 816 |
mixin(defineEnum!("Abc", ubyte, "A", "B", "C", 255)); |
|---|
| 817 |
---- |
|---|
| 818 |
|
|---|
| 819 |
In this case the generated $(D enum) will have a $(D ubyte) |
|---|
| 820 |
representation. */ |
|---|
| 821 |
|
|---|
| 822 |
deprecated template defineEnum(string name, T...) |
|---|
| 823 |
{ |
|---|
| 824 |
static if (is(typeof(cast(T[0]) T[0].init))) |
|---|
| 825 |
enum string defineEnum = |
|---|
| 826 |
enumValuesImpl!(name, T[0], 0, T[1 .. $]) |
|---|
| 827 |
~ enumParserImpl!(name, true, StringsOnly!(T[1 .. $])) |
|---|
| 828 |
~ enumPrinterImpl!(name, true, StringsOnly!(T[1 .. $])); |
|---|
| 829 |
else |
|---|
| 830 |
alias defineEnum!(name, int, T) defineEnum; |
|---|
| 831 |
} |
|---|
| 832 |
|
|---|
| 833 |
unittest |
|---|
| 834 |
{ |
|---|
| 835 |
mixin(defineEnum!("_24b455e148a38a847d65006bca25f7fe", |
|---|
| 836 |
"A1", 1, "B1", "C1")); |
|---|
| 837 |
auto a = _24b455e148a38a847d65006bca25f7fe.A1; |
|---|
| 838 |
assert(enumToString(a) == "A1"); |
|---|
| 839 |
_24b455e148a38a847d65006bca25f7fe b; |
|---|
| 840 |
assert(enumFromString("B1", b) |
|---|
| 841 |
&& b == _24b455e148a38a847d65006bca25f7fe.B1); |
|---|
| 842 |
} |
|---|
| 843 |
|
|---|
| 844 |
/** |
|---|
| 845 |
$(D Rebindable!(T)) is a simple, efficient wrapper that behaves just |
|---|
| 846 |
like an object of type $(D T), except that you can reassign it to |
|---|
| 847 |
refer to another object. For completeness, $(D Rebindable!(T)) aliases |
|---|
| 848 |
itself away to $(D T) if $(D T) is a non-const object type. However, |
|---|
| 849 |
$(D Rebindable!(T)) does not compile if $(D T) is a non-class type. |
|---|
| 850 |
|
|---|
| 851 |
Regular $(D const) object references cannot be reassigned: |
|---|
| 852 |
|
|---|
| 853 |
---- |
|---|
| 854 |
class Widget { int x; int y() const { return a; } } |
|---|
| 855 |
const a = new Widget; |
|---|
| 856 |
a.y(); // fine |
|---|
| 857 |
a.x = 5; // error! can't modify const a |
|---|
| 858 |
a = new Widget; // error! can't modify const a |
|---|
| 859 |
---- |
|---|
| 860 |
|
|---|
| 861 |
However, $(D Rebindable!(Widget)) does allow reassignment, while |
|---|
| 862 |
otherwise behaving exactly like a $(D const Widget): |
|---|
| 863 |
|
|---|
| 864 |
---- |
|---|
| 865 |
auto a = Rebindable!(const Widget)(new Widget); |
|---|
| 866 |
a.y(); // fine |
|---|
| 867 |
a.x = 5; // error! can't modify const a |
|---|
| 868 |
a = new Widget; // fine |
|---|
| 869 |
---- |
|---|
| 870 |
|
|---|
| 871 |
You may want to use $(D Rebindable) when you want to have mutable |
|---|
| 872 |
storage referring to $(D const) objects, for example an array of |
|---|
| 873 |
references that must be sorted in place. $(D Rebindable) does not |
|---|
| 874 |
break the soundness of D's type system and does not incur any of the |
|---|
| 875 |
risks usually associated with $(D cast). |
|---|
| 876 |
|
|---|
| 877 |
*/ |
|---|
| 878 |
template Rebindable(T) if (is(T == class) || is(T == interface) || isArray!(T)) |
|---|
| 879 |
{ |
|---|
| 880 |
static if (!is(T X == const(U), U) && !is(T X == immutable(U), U)) |
|---|
| 881 |
{ |
|---|
| 882 |
alias T Rebindable; |
|---|
| 883 |
} |
|---|
| 884 |
else static if (isArray!(T)) |
|---|
| 885 |
{ |
|---|
| 886 |
alias const(ElementType!(T))[] Rebindable; |
|---|
| 887 |
} |
|---|
| 888 |
else |
|---|
| 889 |
{ |
|---|
| 890 |
struct Rebindable |
|---|
| 891 |
{ |
|---|
| 892 |
private union |
|---|
| 893 |
{ |
|---|
| 894 |
T original; |
|---|
| 895 |
U stripped; |
|---|
| 896 |
} |
|---|
| 897 |
void opAssign(T another) |
|---|
| 898 |
{ |
|---|
| 899 |
stripped = cast(U) another; |
|---|
| 900 |
} |
|---|
| 901 |
void opAssign(Rebindable another) |
|---|
| 902 |
{ |
|---|
| 903 |
stripped = another.stripped; |
|---|
| 904 |
} |
|---|
| 905 |
static if (is(T == const U)) |
|---|
| 906 |
{ |
|---|
| 907 |
// safely assign immutable to const |
|---|
| 908 |
void opAssign(Rebindable!(immutable U) another) |
|---|
| 909 |
{ |
|---|
| 910 |
stripped = another.stripped; |
|---|
| 911 |
} |
|---|
| 912 |
} |
|---|
| 913 |
this(T initializer) |
|---|
| 914 |
{ |
|---|
| 915 |
opAssign(initializer); |
|---|
| 916 |
} |
|---|
| 917 |
|
|---|
| 918 |
@property ref T get() { |
|---|
| 919 |
return original; |
|---|
| 920 |
} |
|---|
| 921 |
|
|---|
| 922 |
alias get this; |
|---|
| 923 |
} |
|---|
| 924 |
} |
|---|
| 925 |
} |
|---|
| 926 |
|
|---|
| 927 |
/** |
|---|
| 928 |
Convenience function for creating a $(D Rebindable) using automatic type |
|---|
| 929 |
inference. |
|---|
| 930 |
*/ |
|---|
| 931 |
Rebindable!(T) rebindable(T)(T obj) |
|---|
| 932 |
if (is(T == class) || is(T == interface) || isArray!(T)) |
|---|
| 933 |
{ |
|---|
| 934 |
typeof(return) ret; |
|---|
| 935 |
ret = obj; |
|---|
| 936 |
return ret; |
|---|
| 937 |
} |
|---|
| 938 |
|
|---|
| 939 |
/** |
|---|
| 940 |
This function simply returns the $(D Rebindable) object passed in. It's useful |
|---|
| 941 |
in generic programming cases when a given object may be either a regular |
|---|
| 942 |
$(D class) or a $(D Rebindable). |
|---|
| 943 |
*/ |
|---|
| 944 |
Rebindable!(T) rebindable(T)(Rebindable!(T) obj) |
|---|
| 945 |
{ |
|---|
| 946 |
return obj; |
|---|
| 947 |
} |
|---|
| 948 |
|
|---|
| 949 |
unittest |
|---|
| 950 |
{ |
|---|
| 951 |
interface CI { const int foo(); } |
|---|
| 952 |
class C : CI { int foo() const { return 42; } } |
|---|
| 953 |
Rebindable!(C) obj0; |
|---|
| 954 |
static assert(is(typeof(obj0) == C)); |
|---|
| 955 |
|
|---|
| 956 |
Rebindable!(const(C)) obj1; |
|---|
| 957 |
static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof); |
|---|
| 958 |
static assert(is(typeof(obj1.stripped) == C)); |
|---|
| 959 |
obj1 = new C; |
|---|
| 960 |
assert(obj1.get !is null); |
|---|
| 961 |
obj1 = new const(C); |
|---|
| 962 |
assert(obj1.get !is null); |
|---|
| 963 |
|
|---|
| 964 |
Rebindable!(immutable(C)) obj2; |
|---|
| 965 |
static assert(is(typeof(obj2.get) == immutable(C))); |
|---|
| 966 |
static assert(is(typeof(obj2.stripped) == C)); |
|---|
| 967 |
obj2 = new immutable(C); |
|---|
| 968 |
assert(obj1.get !is null); |
|---|
| 969 |
|
|---|
| 970 |
// test opDot |
|---|
| 971 |
assert(obj2.foo == 42); |
|---|
| 972 |
|
|---|
| 973 |
interface I { final int foo() const { return 42; } } |
|---|
| 974 |
Rebindable!(I) obj3; |
|---|
| 975 |
static assert(is(typeof(obj3) == I)); |
|---|
| 976 |
|
|---|
| 977 |
Rebindable!(const I) obj4; |
|---|
| 978 |
static assert(is(typeof(obj4.get) == const I)); |
|---|
| 979 |
static assert(is(typeof(obj4.stripped) == I)); |
|---|
| 980 |
static assert(is(typeof(obj4.foo()) == int)); |
|---|
| 981 |
obj4 = new class I {}; |
|---|
| 982 |
|
|---|
| 983 |
Rebindable!(immutable C) obj5i; |
|---|
| 984 |
Rebindable!(const C) obj5c; |
|---|
| 985 |
obj5c = obj5c; |
|---|
| 986 |
obj5c = obj5i; |
|---|
| 987 |
obj5i = obj5i; |
|---|
| 988 |
static assert(!__traits(compiles, obj5i = obj5c)); |
|---|
| 989 |
|
|---|
| 990 |
// Test the convenience functions. |
|---|
| 991 |
auto obj5convenience = rebindable(obj5i); |
|---|
| 992 |
assert(obj5convenience is obj5i); |
|---|
| 993 |
|
|---|
| 994 |
auto obj6 = rebindable(new immutable(C)); |
|---|
| 995 |
static assert(is(typeof(obj6) == Rebindable!(immutable C))); |
|---|
| 996 |
assert(obj6.foo == 42); |
|---|
| 997 |
|
|---|
| 998 |
auto obj7 = rebindable(new C); |
|---|
| 999 |
CI interface1 = obj7; |
|---|
| 1000 |
auto interfaceRebind1 = rebindable(interface1); |
|---|
| 1001 |
assert(interfaceRebind1.foo == 42); |
|---|
| 1002 |
|
|---|
| 1003 |
const interface2 = interface1; |
|---|
| 1004 |
auto interfaceRebind2 = rebindable(interface2); |
|---|
| 1005 |
assert(interfaceRebind2.foo == 42); |
|---|
| 1006 |
|
|---|
| 1007 |
auto arr = [1,2,3,4,5]; |
|---|
| 1008 |
const arrConst = arr; |
|---|
| 1009 |
assert(rebindable(arr) == arr); |
|---|
| 1010 |
assert(rebindable(arrConst) == arr); |
|---|
| 1011 |
} |
|---|
| 1012 |
|
|---|
| 1013 |
/** |
|---|
| 1014 |
Order the provided members to minimize size while preserving alignment. |
|---|
| 1015 |
Returns a declaration to be mixed in. |
|---|
| 1016 |
|
|---|
| 1017 |
Example: |
|---|
| 1018 |
--- |
|---|
| 1019 |
struct Banner { |
|---|
| 1020 |
mixin(alignForSize!(byte[6], double)(["name", "height"])); |
|---|
| 1021 |
} |
|---|
| 1022 |
--- |
|---|
| 1023 |
|
|---|
| 1024 |
Alignment is not always optimal for 80-bit reals, nor for structs declared |
|---|
| 1025 |
as align(1). |
|---|
| 1026 |
BUG: bugzilla 2029 prevents the signature from being (string[] names...), |
|---|
| 1027 |
so we need to use an ugly array literal instead. |
|---|
| 1028 |
*/ |
|---|
| 1029 |
char [] alignForSize(E...)(string[E.length] names) |
|---|
| 1030 |
{ |
|---|
| 1031 |
// Sort all of the members by .alignof. |
|---|
| 1032 |
// BUG: Alignment is not always optimal for align(1) structs |
|---|
| 1033 |
// or 80-bit reals. |
|---|
| 1034 |
// TRICK: Use the fact that .alignof is always a power of 2, |
|---|
| 1035 |
// and maximum 16 on extant systems. Thus, we can perform |
|---|
| 1036 |
// a very limited radix sort. |
|---|
| 1037 |
// Contains the members with .alignof = 64,32,16,8,4,2,1 |
|---|
| 1038 |
int [][] alignlist; // workaround for bugzilla 2569 |
|---|
| 1039 |
alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 |
|---|
| 1040 |
char[][] declaration; |
|---|
| 1041 |
foreach(int i_bug,T; E) { |
|---|
| 1042 |
int i = i_bug; // workaround for bugzilla 2564 (D2 only) |
|---|
| 1043 |
declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; |
|---|
| 1044 |
int a = T.alignof; |
|---|
| 1045 |
int k = a>=64? 0 : a>=32? 1 : a>=16? 2 : a>=8? 3 : a>=4? 4 : a>=2? 5 : 6; |
|---|
| 1046 |
alignlist[k]~=i; |
|---|
| 1047 |
} |
|---|
| 1048 |
char [] s; |
|---|
| 1049 |
foreach(q; alignlist) { |
|---|
| 1050 |
foreach(int i; q) { |
|---|
| 1051 |
s~= declaration[i]; |
|---|
| 1052 |
} |
|---|
| 1053 |
} |
|---|
| 1054 |
return s; |
|---|
| 1055 |
} |
|---|
| 1056 |
|
|---|
| 1057 |
unittest { |
|---|
| 1058 |
// assert(alignForSize!(int[], char[3], short, double[5])(["x", "y","z", "w"]) =="double[5u] w;\nint[] x;\nshort z;\nchar[3u] y;\n"); |
|---|
| 1059 |
struct Foo{ int x; } |
|---|
| 1060 |
// assert(alignForSize!(ubyte, Foo, cdouble)(["x", "y","z"]) =="cdouble z;\nFoo y;\nubyte x;\n"); |
|---|
| 1061 |
} |
|---|
| 1062 |
|
|---|
| 1063 |
/*--* |
|---|
| 1064 |
First-class reference type |
|---|
| 1065 |
*/ |
|---|
| 1066 |
struct Ref(T) |
|---|
| 1067 |
{ |
|---|
| 1068 |
private T * _p; |
|---|
| 1069 |
this(ref T value) { _p = &value; } |
|---|
| 1070 |
ref T opDot() { return *_p; } |
|---|
| 1071 |
/*ref*/ T opImplicitCastTo() { return *_p; } |
|---|
| 1072 |
ref T value() { return *_p; } |
|---|
| 1073 |
|
|---|
| 1074 |
void opAssign(T value) |
|---|
| 1075 |
{ |
|---|
| 1076 |
*_p = value; |
|---|
| 1077 |
} |
|---|
| 1078 |
void opAssign(T * value) |
|---|
| 1079 |
{ |
|---|
| 1080 |
_p = value; |
|---|
| 1081 |
} |
|---|
| 1082 |
} |
|---|
| 1083 |
|
|---|
| 1084 |
unittest |
|---|
| 1085 |
{ |
|---|
| 1086 |
Ref!(int) x; |
|---|
| 1087 |
int y = 42; |
|---|
| 1088 |
x = &y; |
|---|
| 1089 |
assert(x.value == 42); |
|---|
| 1090 |
x = 5; |
|---|
| 1091 |
assert(x.value == 5); |
|---|
| 1092 |
assert(y == 5); |
|---|
| 1093 |
} |
|---|
| 1094 |
|
|---|
| 1095 |
/+ |
|---|
| 1096 |
|
|---|
| 1097 |
/** |
|---|
| 1098 |
Defines a value paired with a distinctive "null" state that denotes |
|---|
| 1099 |
the absence of a valud value. If default constructed, a $(D |
|---|
| 1100 |
Nullable!T) object starts in the null state. Assigning it renders it |
|---|
| 1101 |
non-null. Calling $(D nullify) can nullify it again. |
|---|
| 1102 |
|
|---|
| 1103 |
Example: |
|---|
| 1104 |
---- |
|---|
| 1105 |
Nullable!int a; |
|---|
| 1106 |
assert(a.isNull); |
|---|
| 1107 |
a = 5; |
|---|
| 1108 |
assert(!a.isNull); |
|---|
| 1109 |
assert(a == 5); |
|---|
| 1110 |
---- |
|---|
| 1111 |
|
|---|
| 1112 |
Practically $(D Nullable!T) stores a $(D T) and a $(D bool). |
|---|
| 1113 |
*/ |
|---|
| 1114 |
struct Nullable(T) |
|---|
| 1115 |
{ |
|---|
| 1116 |
private T _value; |
|---|
| 1117 |
private bool _isNull = true; |
|---|
| 1118 |
|
|---|
| 1119 |
/** |
|---|
| 1120 |
Constructor initializing $(D this) with $(D value). |
|---|
| 1121 |
*/ |
|---|
| 1122 |
this(T value) |
|---|
| 1123 |
{ |
|---|
| 1124 |
_value = value; |
|---|
| 1125 |
_isNull = false; |
|---|
| 1126 |
} |
|---|
| 1127 |
|
|---|
| 1128 |
/** |
|---|
| 1129 |
Returns $(D true) if and only if $(D this) is in the null state. |
|---|
| 1130 |
*/ |
|---|
| 1131 |
bool isNull() |
|---|
| 1132 |
{ |
|---|
| 1133 |
return _isNull; |
|---|
| 1134 |
} |
|---|
| 1135 |
|
|---|
| 1136 |
/** |
|---|
| 1137 |
Forces $(D this) to the null state. |
|---|
| 1138 |
*/ |
|---|
| 1139 |
void nullify() |
|---|
| 1140 |
{ |
|---|
| 1141 |
// destroy |
|---|
| 1142 |
//static if (is(typeof(_value.__dtor()))) _value.__dtor(); |
|---|
| 1143 |
_isNull = true; |
|---|
| 1144 |
} |
|---|
| 1145 |
|
|---|
| 1146 |
/** |
|---|
| 1147 |
Assigns $(D value) to the internally-held state. If the assignment |
|---|
| 1148 |
succeeds, $(D this) becomes non-null. |
|---|
| 1149 |
*/ |
|---|
| 1150 |
void opAssign(T value) |
|---|
| 1151 |
{ |
|---|
| 1152 |
_value = value; |
|---|
| 1153 |
_isNull = false; |
|---|
| 1154 |
} |
|---|
| 1155 |
|
|---|
| 1156 |
/** |
|---|
| 1157 |
Gets the value. Throws an exception if $(D this) is in the null |
|---|
| 1158 |
state. This function is also called for the implicit conversion to $(D |
|---|
| 1159 |
T). |
|---|
| 1160 |
*/ |
|---|
| 1161 |
ref T get() |
|---|
| 1162 |
{ |
|---|
| 1163 |
enforce(!isNull); |
|---|
| 1164 |
return _value; |
|---|
| 1165 |
} |
|---|
| 1166 |
|
|---|
| 1167 |
/** |
|---|
| 1168 |
Implicitly converts to $(D T). Throws an exception if $(D this) is in |
|---|
| 1169 |
the null state. |
|---|
| 1170 |
*/ |
|---|
| 1171 |
alias get this; |
|---|
| 1172 |
} |
|---|
| 1173 |
|
|---|
| 1174 |
unittest |
|---|
| 1175 |
{ |
|---|
| 1176 |
Nullable!int a; |
|---|
| 1177 |
assert(a.isNull); |
|---|
| 1178 |
a = 5; |
|---|
| 1179 |
assert(!a.isNull); |
|---|
| 1180 |
assert(a == 5); |
|---|
| 1181 |
} |
|---|
| 1182 |
|
|---|
| 1183 |
/** |
|---|
| 1184 |
Just like $(D Nullable!T), except that the null state is defined as a |
|---|
| 1185 |
particular value. For example, $(D Nullable!(uint, uint.max)) is an |
|---|
| 1186 |
$(D uint) that sets aside the value $(D uint.max) to denote a null |
|---|
| 1187 |
state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D |
|---|
| 1188 |
Nullable!T) because it does not need to store an extra $(D bool). |
|---|
| 1189 |
*/ |
|---|
| 1190 |
struct Nullable(T, T nullValue) |
|---|
| 1191 |
{ |
|---|
| 1192 |
private T _value = nullValue; |
|---|
| 1193 |
|
|---|
| 1194 |
/** |
|---|
| 1195 |
Constructor initializing $(D this) with $(D value). |
|---|
| 1196 |
*/ |
|---|
| 1197 |
this(T value) |
|---|
| 1198 |
{ |
|---|
| 1199 |
_value = value; |
|---|
| 1200 |
} |
|---|
| 1201 |
|
|---|
| 1202 |
/** |
|---|
| 1203 |
Returns $(D true) if and only if $(D this) is in the null state. |
|---|
| 1204 |
*/ |
|---|
| 1205 |
bool isNull() |
|---|
| 1206 |
{ |
|---|
| 1207 |
return _value == nullValue; |
|---|
| 1208 |
} |
|---|
| 1209 |
|
|---|
| 1210 |
/** |
|---|
| 1211 |
Forces $(D this) to the null state. |
|---|
| 1212 |
*/ |
|---|
| 1213 |
void nullify() |
|---|
| 1214 |
{ |
|---|
| 1215 |
_value = nullValue; |
|---|
| 1216 |
} |
|---|
| 1217 |
|
|---|
| 1218 |
/** |
|---|
| 1219 |
Assigns $(D value) to the internally-held state. No null checks are |
|---|
| 1220 |
made. |
|---|
| 1221 |
*/ |
|---|
| 1222 |
void opAssign(T value) |
|---|
| 1223 |
{ |
|---|
| 1224 |
_value = value; |
|---|
| 1225 |
} |
|---|
| 1226 |
|
|---|
| 1227 |
/** |
|---|
| 1228 |
Gets the value. Throws an exception if $(D this) is in the null |
|---|
| 1229 |
state. This function is also called for the implicit conversion to $(D |
|---|
| 1230 |
T). |
|---|
| 1231 |
*/ |
|---|
| 1232 |
ref T get() |
|---|
| 1233 |
{ |
|---|
| 1234 |
enforce(!isNull); |
|---|
| 1235 |
return _value; |
|---|
| 1236 |
} |
|---|
| 1237 |
|
|---|
| 1238 |
/** |
|---|
| 1239 |
Implicitly converts to $(D T). Throws an exception if $(D this) is in |
|---|
| 1240 |
the null state. |
|---|
| 1241 |
*/ |
|---|
| 1242 |
alias get this; |
|---|
| 1243 |
} |
|---|
| 1244 |
|
|---|
| 1245 |
unittest |
|---|
| 1246 |
{ |
|---|
| 1247 |
Nullable!(int, int.min) a; |
|---|
| 1248 |
assert(a.isNull); |
|---|
| 1249 |
a = 5; |
|---|
| 1250 |
assert(!a.isNull); |
|---|
| 1251 |
assert(a == 5); |
|---|
| 1252 |
} |
|---|
| 1253 |
|
|---|
| 1254 |
/** |
|---|
| 1255 |
Just like $(D Nullable!T), except that the object refers to a value |
|---|
| 1256 |
sitting elsewhere in memory. This makes assignments overwrite the |
|---|
| 1257 |
initially assigned value. Internally $(D NullableRef!T) only stores a |
|---|
| 1258 |
pointer to $(D T) (i.e., $(D Nullable!T.sizeof == (T*).sizeof)). |
|---|
| 1259 |
*/ |
|---|
| 1260 |
struct NullableRef(T) |
|---|
| 1261 |
{ |
|---|
| 1262 |
private T* _value; |
|---|
| 1263 |
|
|---|
| 1264 |
/** |
|---|
| 1265 |
Constructor binding $(D this) with $(D value). |
|---|
| 1266 |
*/ |
|---|
| 1267 |
this(T * value) |
|---|
| 1268 |
{ |
|---|
| 1269 |
_value = value; |
|---|
| 1270 |
} |
|---|
| 1271 |
|
|---|
| 1272 |
/** |
|---|
| 1273 |
Binds the internal state to $(D value). |
|---|
| 1274 |
*/ |
|---|
| 1275 |
void bind(T * value) |
|---|
| 1276 |
{ |
|---|
| 1277 |
_value = value; |
|---|
| 1278 |
} |
|---|
| 1279 |
|
|---|
| 1280 |
/** |
|---|
| 1281 |
Returns $(D true) if and only if $(D this) is in the null state. |
|---|
| 1282 |
*/ |
|---|
| 1283 |
bool isNull() |
|---|
| 1284 |
{ |
|---|
| 1285 |
return _value is null; |
|---|
| 1286 |
} |
|---|
| 1287 |
|
|---|
| 1288 |
/** |
|---|
| 1289 |
Forces $(D this) to the null state. |
|---|
| 1290 |
*/ |
|---|
| 1291 |
void nullify() |
|---|
| 1292 |
{ |
|---|
| 1293 |
_value = null; |
|---|
| 1294 |
} |
|---|
| 1295 |
|
|---|
| 1296 |
/** |
|---|
| 1297 |
Assigns $(D value) to the internally-held state. |
|---|
| 1298 |
*/ |
|---|
| 1299 |
void opAssign(T value) |
|---|
| 1300 |
{ |
|---|
| 1301 |
enforce(_value); |
|---|
| 1302 |
*_value = value; |
|---|
| 1303 |
} |
|---|
| 1304 |
|
|---|
| 1305 |
/** |
|---|
| 1306 |
Gets the value. Throws an exception if $(D this) is in the null |
|---|
| 1307 |
state. This function is also called for the implicit conversion to $(D |
|---|
| 1308 |
T). |
|---|
| 1309 |
*/ |
|---|
| 1310 |
ref T get() |
|---|
| 1311 |
{ |
|---|
| 1312 |
enforce(!isNull); |
|---|
| 1313 |
return *_value; |
|---|
| 1314 |
} |
|---|
| 1315 |
|
|---|
| 1316 |
/** |
|---|
| 1317 |
Implicitly converts to $(D T). Throws an exception if $(D this) is in |
|---|
| 1318 |
the null state. |
|---|
| 1319 |
*/ |
|---|
| 1320 |
alias get this; |
|---|
| 1321 |
} |
|---|
| 1322 |
|
|---|
| 1323 |
unittest |
|---|
| 1324 |
{ |
|---|
| 1325 |
int x = 5; |
|---|
| 1326 |
auto a = NullableRef!(int)(&x); |
|---|
| 1327 |
assert(!a.isNull); |
|---|
| 1328 |
assert(a == 5); |
|---|
| 1329 |
a = 42; |
|---|
| 1330 |
assert(!a.isNull); |
|---|
| 1331 |
assert(a == 42); |
|---|
| 1332 |
} |
|---|
| 1333 |
|
|---|
| 1334 |
+/ |
|---|
| 1335 |
|
|---|
| 1336 |
|
|---|
| 1337 |
/** |
|---|
| 1338 |
$(D BlackHole!Base) is a subclass of $(D Base) which automatically implements |
|---|
| 1339 |
all abstract member functions in $(D Base) as do-nothing functions. Each |
|---|
| 1340 |
auto-implemented function just returns the default value of the return type |
|---|
| 1341 |
without doing anything. |
|---|
| 1342 |
|
|---|
| 1343 |
The name came from |
|---|
| 1344 |
$(WEB search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole) |
|---|
| 1345 |
Perl module by Sean M. Burke. |
|---|
| 1346 |
|
|---|
| 1347 |
Example: |
|---|
| 1348 |
-------------------- |
|---|
| 1349 |
abstract class C |
|---|
| 1350 |
{ |
|---|
| 1351 |
int m_value; |
|---|
| 1352 |
this(int v) { m_value = v; } |
|---|
| 1353 |
int value() @property { return m_value; } |
|---|
| 1354 |
|
|---|
| 1355 |
abstract real realValue() @property; |
|---|
| 1356 |
abstract void doSomething(); |
|---|
| 1357 |
} |
|---|
| 1358 |
|
|---|
| 1359 |
void main() |
|---|
| 1360 |
{ |
|---|
| 1361 |
auto c = new BlackHole!C(42); |
|---|
| 1362 |
writeln(c.value); // prints "42" |
|---|
| 1363 |
|
|---|
| 1364 |
// Abstract functions are implemented as do-nothing: |
|---|
| 1365 |
writeln(c.realValue); // prints "NaN" |
|---|
| 1366 |
c.doSomething(); // does nothing |
|---|
| 1367 |
} |
|---|
| 1368 |
-------------------- |
|---|
| 1369 |
|
|---|
| 1370 |
See_Also: |
|---|
| 1371 |
AutoImplement, generateEmptyFunction |
|---|
| 1372 |
*/ |
|---|
| 1373 |
template BlackHole(Base) |
|---|
| 1374 |
{ |
|---|
| 1375 |
alias AutoImplement!(Base, generateEmptyFunction, isAbstractFunction) |
|---|
| 1376 |
BlackHole; |
|---|
| 1377 |
} |
|---|
| 1378 |
|
|---|
| 1379 |
unittest |
|---|
| 1380 |
{ |
|---|
| 1381 |
// return default |
|---|
| 1382 |
{ |
|---|
| 1383 |
interface I_1 { real test(); } |
|---|
| 1384 |
auto o = new BlackHole!I_1; |
|---|
| 1385 |
assert(o.test() !<>= 0); // NaN |
|---|
| 1386 |
} |
|---|
| 1387 |
// doc example |
|---|
| 1388 |
{ |
|---|
| 1389 |
static class C |
|---|
| 1390 |
{ |
|---|
| 1391 |
int m_value; |
|---|
| 1392 |
this(int v) { m_value = v; } |
|---|
| 1393 |
int value() @property { return m_value; } |
|---|
| 1394 |
|
|---|
| 1395 |
abstract real realValue() @property; |
|---|
| 1396 |
abstract void doSomething(); |
|---|
| 1397 |
} |
|---|
| 1398 |
|
|---|
| 1399 |
auto c = new BlackHole!C(42); |
|---|
| 1400 |
assert(c.value == 42); |
|---|
| 1401 |
|
|---|
| 1402 |
assert(c.realValue !<>= 0); // NaN |
|---|
| 1403 |
c.doSomething(); |
|---|
| 1404 |
} |
|---|
| 1405 |
} |
|---|
| 1406 |
|
|---|
| 1407 |
|
|---|
| 1408 |
/** |
|---|
| 1409 |
$(D WhiteHole!Base) is a subclass of $(D Base) which automatically implements |
|---|
| 1410 |
all abstract member functions as throw-always functions. Each auto-implemented |
|---|
| 1411 |
function fails with throwing an $(D Error) and does never return. Useful for |
|---|
| 1412 |
trapping use of not-yet-implemented functions. |
|---|
| 1413 |
|
|---|
| 1414 |
The name came from |
|---|
| 1415 |
$(WEB search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole) |
|---|
| 1416 |
Perl module by Michael G Schwern. |
|---|
| 1417 |
|
|---|
| 1418 |
Example: |
|---|
| 1419 |
-------------------- |
|---|
| 1420 |
class C |
|---|
| 1421 |
{ |
|---|
| 1422 |
abstract void notYetImplemented(); |
|---|
| 1423 |
} |
|---|
| 1424 |
|
|---|
| 1425 |
void main() |
|---|
| 1426 |
{ |
|---|
| 1427 |
auto c = new WhiteHole!C; |
|---|
| 1428 |
c.notYetImplemented(); // throws an Error |
|---|
| 1429 |
} |
|---|
| 1430 |
-------------------- |
|---|
| 1431 |
|
|---|
| 1432 |
BUGS: |
|---|
| 1433 |
Nothrow functions cause program to abort in release mode because the trap is |
|---|
| 1434 |
implemented with $(D assert(0)) for nothrow functions. |
|---|
| 1435 |
|
|---|
| 1436 |
See_Also: |
|---|
| 1437 |
AutoImplement, generateAssertTrap |
|---|
| 1438 |
*/ |
|---|
| 1439 |
template WhiteHole(Base) |
|---|
| 1440 |
{ |
|---|
| 1441 |
alias AutoImplement!(Base, generateAssertTrap, isAbstractFunction) |
|---|
| 1442 |
WhiteHole; |
|---|
| 1443 |
} |
|---|
| 1444 |
|
|---|
| 1445 |
// / ditto |
|---|
| 1446 |
class NotImplementedError : Error |
|---|
| 1447 |
{ |
|---|
| 1448 |
this(string method) |
|---|
| 1449 |
{ |
|---|
| 1450 |
super(method ~ " is not implemented"); |
|---|
| 1451 |
} |
|---|
| 1452 |
} |
|---|
| 1453 |
|
|---|
| 1454 |
unittest |
|---|
| 1455 |
{ |
|---|
| 1456 |
// nothrow |
|---|
| 1457 |
debug // see the BUGS above |
|---|
| 1458 |
{ |
|---|
| 1459 |
interface I_1 |
|---|
| 1460 |
{ |
|---|
| 1461 |
void foo(); |
|---|
| 1462 |
void bar() nothrow; |
|---|
| 1463 |
} |
|---|
| 1464 |
auto o = new WhiteHole!I_1; |
|---|
| 1465 |
uint trap; |
|---|
| 1466 |
try { o.foo(); } catch (Error e) { ++trap; } |
|---|
| 1467 |
assert(trap == 1); |
|---|
| 1468 |
try { o.bar(); } catch (Error e) { ++trap; } |
|---|
| 1469 |
assert(trap == 2); |
|---|
| 1470 |
} |
|---|
| 1471 |
// doc example |
|---|
| 1472 |
{ |
|---|
| 1473 |
static class C |
|---|
| 1474 |
{ |
|---|
| 1475 |
abstract void notYetImplemented(); |
|---|
| 1476 |
} |
|---|
| 1477 |
|
|---|
| 1478 |
auto c = new WhiteHole!C; |
|---|
| 1479 |
try |
|---|
| 1480 |
{ |
|---|
| 1481 |
c.notYetImplemented(); |
|---|
| 1482 |
assert(0); |
|---|
| 1483 |
} |
|---|
| 1484 |
catch (Error e) {} |
|---|
| 1485 |
} |
|---|
| 1486 |
} |
|---|
| 1487 |
|
|---|
| 1488 |
|
|---|
| 1489 |
/** |
|---|
| 1490 |
$(D AutoImplement) automatically implements (by default) all abstract member |
|---|
| 1491 |
functions in the class or interface $(D Base) in specified way. |
|---|
| 1492 |
|
|---|
| 1493 |
Params: |
|---|
| 1494 |
how = template which specifies _how functions will be implemented/overridden. |
|---|
| 1495 |
|
|---|
| 1496 |
Two arguments are passed to $(D how): the type $(D Base) and an alias |
|---|
| 1497 |
to an implemented function. Then $(D how) must return an implemented |
|---|
| 1498 |
function body as a string. |
|---|
| 1499 |
|
|---|
| 1500 |
The generated function body can use these keywords: |
|---|
| 1501 |
$(UL |
|---|
| 1502 |
$(LI $(D a0), $(D a1), …: arguments passed to the function;) |
|---|
| 1503 |
$(LI $(D args): a tuple of the arguments;) |
|---|
| 1504 |
$(LI $(D self): an alias to the function itself;) |
|---|
| 1505 |
$(LI $(D parent): an alias to the overridden function (if any).) |
|---|
| 1506 |
) |
|---|
| 1507 |
|
|---|
| 1508 |
You may want to use templated property functions (instead of Implicit |
|---|
| 1509 |
Template Properties) to generate complex functions: |
|---|
| 1510 |
-------------------- |
|---|
| 1511 |
// Prints log messages for each call to overridden functions. |
|---|
| 1512 |
string generateLogger(C, alias fun)() @property |
|---|
| 1513 |
{ |
|---|
| 1514 |
enum qname = C.stringof ~ "." ~ __traits(identifier, fun); |
|---|
| 1515 |
string stmt; |
|---|
| 1516 |
|
|---|
| 1517 |
stmt ~= q{ struct Importer { import std.stdio; } }; |
|---|
| 1518 |
stmt ~= `Importer.writeln$(LPAREN)"Log: ` ~ qname ~ `(", args, ")"$(RPAREN);`; |
|---|
| 1519 |
static if (!__traits(isAbstractFunction, fun)) |
|---|
| 1520 |
{ |
|---|
| 1521 |
static if (is(typeof(return) == void)) |
|---|
| 1522 |
stmt ~= q{ parent(args); }; |
|---|
| 1523 |
else |
|---|
| 1524 |
stmt ~= q{ |
|---|
| 1525 |
auto r = parent(args); |
|---|
| 1526 |
Importer.writeln("--> ", r); |
|---|
| 1527 |
return r; |
|---|
| 1528 |
}; |
|---|
| 1529 |
} |
|---|
| 1530 |
return stmt; |
|---|
| 1531 |
} |
|---|
| 1532 |
-------------------- |
|---|
| 1533 |
|
|---|
| 1534 |
what = template which determines _what functions should be |
|---|
| 1535 |
implemented/overridden. |
|---|
| 1536 |
|
|---|
| 1537 |
An argument is passed to $(D what): an alias to a non-final member |
|---|
| 1538 |
function in $(D Base). Then $(D what) must return a boolean value. |
|---|
| 1539 |
Return $(D true) to indicate that the passed function should be |
|---|
| 1540 |
implemented/overridden. |
|---|
| 1541 |
|
|---|
| 1542 |
-------------------- |
|---|
| 1543 |
// Sees if fun returns something. |
|---|
| 1544 |
template hasValue(alias fun) |
|---|
| 1545 |
{ |
|---|
| 1546 |
enum bool hasValue = !is(ReturnType!(fun) == void); |
|---|
| 1547 |
} |
|---|
| 1548 |
-------------------- |
|---|
| 1549 |
|
|---|
| 1550 |
|
|---|
| 1551 |
Note: |
|---|
| 1552 |
|
|---|
| 1553 |
Generated code is inserted in the scope of $(D std.typecons) module. Thus, |
|---|
| 1554 |
any useful functions outside $(D std.typecons) cannot be used in the generated |
|---|
| 1555 |
code. To workaround this problem, you may $(D import) necessary things in a |
|---|
| 1556 |
local struct, as done in the $(D generateLogger()) template in the above |
|---|
| 1557 |
example. |
|---|
| 1558 |
|
|---|
| 1559 |
|
|---|
| 1560 |
BUGS: |
|---|
| 1561 |
|
|---|
| 1562 |
$(UL |
|---|
| 1563 |
$(LI Variadic arguments to constructors are not forwarded to super.) |
|---|
| 1564 |
$(LI Deep interface inheritance causes compile error with messages like |
|---|
| 1565 |
"Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar |
|---|
| 1566 |
does not override any function". [$(BUGZILLA 2525), $(BUGZILLA 3525)] ) |
|---|
| 1567 |
$(LI The $(D parent) keyword is actually a delegate to the super class' |
|---|
| 1568 |
corresponding member function. [$(BUGZILLA 2540)] ) |
|---|
| 1569 |
$(LI Using alias template parameter in $(D how) and/or $(D what) may cause |
|---|
| 1570 |
strange compile error. Use template tuple parameter instead to workaround |
|---|
| 1571 |
this problem. [$(BUGZILLA 4217)] ) |
|---|
| 1572 |
) |
|---|
| 1573 |
*/ |
|---|
| 1574 |
class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base |
|---|
| 1575 |
{ |
|---|
| 1576 |
private alias AutoImplement_Helper!( |
|---|
| 1577 |
"autoImplement_helper_", "Base", Base, how, what ) |
|---|
| 1578 |
autoImplement_helper_; |
|---|
| 1579 |
override mixin(autoImplement_helper_.code); |
|---|
| 1580 |
} |
|---|
| 1581 |
|
|---|
| 1582 |
/* |
|---|
| 1583 |
* Code-generating stuffs are encupsulated in this helper template so that |
|---|
| 1584 |
* namespace pollusion, which can cause name confliction with Base's public |
|---|
| 1585 |
* members, should be minimized. |
|---|
| 1586 |
*/ |
|---|
| 1587 |
private template AutoImplement_Helper(string myName, string baseName, |
|---|
| 1588 |
Base, alias generateMethodBody, alias cherrypickMethod) |
|---|
| 1589 |
{ |
|---|
| 1590 |
private static: |
|---|
| 1591 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1592 |
// Internal stuffs |
|---|
| 1593 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1594 |
|
|---|
| 1595 |
// this would be deprecated by std.typelist.Filter |
|---|
| 1596 |
template staticFilter(alias pred, lst...) |
|---|
| 1597 |
{ |
|---|
| 1598 |
alias staticFilterImpl!(pred, lst).result staticFilter; |
|---|
| 1599 |
} |
|---|
| 1600 |
template staticFilterImpl(alias pred, lst...) |
|---|
| 1601 |
{ |
|---|
| 1602 |
static if (lst.length > 0) |
|---|
| 1603 |
{ |
|---|
| 1604 |
alias staticFilterImpl!(pred, lst[1 .. $]).result tail; |
|---|
| 1605 |
// |
|---|
| 1606 |
static if (true && pred!(lst[0])) |
|---|
| 1607 |
alias TypeTuple!(lst[0], tail) result; |
|---|
| 1608 |
else |
|---|
| 1609 |
alias tail result; |
|---|
| 1610 |
} |
|---|
| 1611 |
else |
|---|
| 1612 |
alias TypeTuple!() result; |
|---|
| 1613 |
} |
|---|
| 1614 |
|
|---|
| 1615 |
// Returns function overload sets in the class C, filtered with pred. |
|---|
| 1616 |
template enumerateOverloads(C, alias pred) |
|---|
| 1617 |
{ |
|---|
| 1618 |
alias enumerateOverloadsImpl!(C, pred, traits_allMembers!(C)).result |
|---|
| 1619 |
enumerateOverloads; |
|---|
| 1620 |
} |
|---|
| 1621 |
template enumerateOverloadsImpl(C, alias pred, names...) |
|---|
| 1622 |
{ |
|---|
| 1623 |
static if (names.length > 0) |
|---|
| 1624 |
{ |
|---|
| 1625 |
alias staticFilter!(pred, MemberFunctionsTuple!(C, ""~names[0])) methods; |
|---|
| 1626 |
alias enumerateOverloadsImpl!(C, pred, names[1 .. $]).result next; |
|---|
| 1627 |
|
|---|
| 1628 |
static if (methods.length > 0) |
|---|
| 1629 |
alias TypeTuple!(OverloadSet!(""~names[0], methods), next) result; |
|---|
| 1630 |
else |
|---|
| 1631 |
alias next result; |
|---|
| 1632 |
} |
|---|
| 1633 |
else |
|---|
| 1634 |
alias TypeTuple!() result; |
|---|
| 1635 |
} |
|---|
| 1636 |
|
|---|
| 1637 |
|
|---|
| 1638 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1639 |
// Target functions |
|---|
| 1640 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1641 |
|
|---|
| 1642 |
// Add a non-final check to the cherrypickMethod. |
|---|
| 1643 |
template canonicalPicker(fun.../+[BUG 4217]+/) |
|---|
| 1644 |
{ |
|---|
| 1645 |
enum bool canonicalPicker = !__traits(isFinalFunction, fun[0]) && |
|---|
| 1646 |
cherrypickMethod!(fun); |
|---|
| 1647 |
} |
|---|
| 1648 |
|
|---|
| 1649 |
/* |
|---|
| 1650 |
* A tuple of overload sets, each item of which consists of functions to be |
|---|
| 1651 |
* implemented by the generated code. |
|---|
| 1652 |
*/ |
|---|
| 1653 |
alias enumerateOverloads!(Base, canonicalPicker) targetOverloadSets; |
|---|
| 1654 |
|
|---|
| 1655 |
/* |
|---|
| 1656 |
* A tuple of the super class' constructors. Used for forwarding |
|---|
| 1657 |
* constructor calls. |
|---|
| 1658 |
*/ |
|---|
| 1659 |
static if (__traits(hasMember, Base, "__ctor")) |
|---|
| 1660 |
alias OverloadSet!("__ctor", __traits(getOverloads, Base, "__ctor")) |
|---|
| 1661 |
ctorOverloadSet; |
|---|
| 1662 |
else |
|---|
| 1663 |
alias OverloadSet!("__ctor") ctorOverloadSet; // empty |
|---|
| 1664 |
|
|---|
| 1665 |
|
|---|
| 1666 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1667 |
// Type information |
|---|
| 1668 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1669 |
|
|---|
| 1670 |
/* |
|---|
| 1671 |
* The generated code will be mixed into AutoImplement, which will be |
|---|
| 1672 |
* instantiated in this module's scope. Thus, any user-defined types are |
|---|
| 1673 |
* out of scope and cannot be used directly (i.e. by their names). |
|---|
| 1674 |
* |
|---|
| 1675 |
* We will use FuncInfo instances for accessing return types and parameter |
|---|
| 1676 |
* types of the implemented functions. The instances will be populated to |
|---|
| 1677 |
* the AutoImplement's scope in a certain way; see the populate() below. |
|---|
| 1678 |
*/ |
|---|
| 1679 |
|
|---|
| 1680 |
// Returns the preferred identifier for the FuncInfo instance for the i-th |
|---|
| 1681 |
// overloaded function with the name. |
|---|
| 1682 |
template INTERNAL_FUNCINFO_ID(string name, size_t i) |
|---|
| 1683 |
{ |
|---|
| 1684 |
enum string INTERNAL_FUNCINFO_ID = "F_" ~ name ~ "_" ~ toStringNow!(i); |
|---|
| 1685 |
} |
|---|
| 1686 |
|
|---|
| 1687 |
/* |
|---|
| 1688 |
* Insert FuncInfo instances about all the target functions here. This |
|---|
| 1689 |
* enables the generated code to access type information via, for example, |
|---|
| 1690 |
* "autoImplement_helper_.F_foo_1". |
|---|
| 1691 |
*/ |
|---|
| 1692 |
template populate(overloads...) |
|---|
| 1693 |
{ |
|---|
| 1694 |
static if (overloads.length > 0) |
|---|
| 1695 |
{ |
|---|
| 1696 |
mixin populate!(overloads[0].name, overloads[0].contents); |
|---|
| 1697 |
mixin populate!(overloads[1 .. $]); |
|---|
| 1698 |
} |
|---|
| 1699 |
} |
|---|
| 1700 |
template populate(string name, methods...) |
|---|
| 1701 |
{ |
|---|
| 1702 |
static if (methods.length > 0) |
|---|
| 1703 |
{ |
|---|
| 1704 |
mixin populate!(name, methods[0 .. $ - 1]); |
|---|
| 1705 |
// |
|---|
| 1706 |
alias methods[$ - 1] target; |
|---|
| 1707 |
enum ith = methods.length - 1; |
|---|
| 1708 |
mixin( "alias FuncInfo!(target) " ~ |
|---|
| 1709 |
INTERNAL_FUNCINFO_ID!(name, ith) ~ ";" ); |
|---|
| 1710 |
} |
|---|
| 1711 |
} |
|---|
| 1712 |
|
|---|
| 1713 |
public mixin populate!(targetOverloadSets); |
|---|
| 1714 |
public mixin populate!( ctorOverloadSet ); |
|---|
| 1715 |
|
|---|
| 1716 |
|
|---|
| 1717 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1718 |
// Code-generating policies |
|---|
| 1719 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1720 |
|
|---|
| 1721 |
/* Common policy configurations for generating constructors and methods. */ |
|---|
| 1722 |
template CommonGeneratingPolicy() |
|---|
| 1723 |
{ |
|---|
| 1724 |
// base class identifier which generated code should use |
|---|
| 1725 |
enum string BASE_CLASS_ID = baseName; |
|---|
| 1726 |
|
|---|
| 1727 |
// FuncInfo instance identifier which generated code should use |
|---|
| 1728 |
template FUNCINFO_ID(string name, size_t i) |
|---|
| 1729 |
{ |
|---|
| 1730 |
enum string FUNCINFO_ID = |
|---|
| 1731 |
myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i); |
|---|
| 1732 |
} |
|---|
| 1733 |
} |
|---|
| 1734 |
|
|---|
| 1735 |
/* Policy configurations for generating constructors. */ |
|---|
| 1736 |
template ConstructorGeneratingPolicy() |
|---|
| 1737 |
{ |
|---|
| 1738 |
mixin CommonGeneratingPolicy; |
|---|
| 1739 |
|
|---|
| 1740 |
/* Generates constructor body. Just forward to the base class' one. */ |
|---|
| 1741 |
string generateFunctionBody(ctor.../+[BUG 4217]+/)() @property |
|---|
| 1742 |
{ |
|---|
| 1743 |
enum varstyle = variadicFunctionStyle!(typeof(&ctor[0])); |
|---|
| 1744 |
|
|---|
| 1745 |
static if (varstyle & (Variadic.C | Variadic.D)) |
|---|
| 1746 |
{ |
|---|
| 1747 |
// the argptr-forwarding problem |
|---|
| 1748 |
pragma(msg, "Warning: AutoImplement!(", Base, ") ", |
|---|
| 1749 |
"ignored variadic arguments to the constructor ", |
|---|
| 1750 |
FunctionTypeOf!(typeof(&ctor[0])) ); |
|---|
| 1751 |
} |
|---|
| 1752 |
return "super(args);"; |
|---|
| 1753 |
} |
|---|
| 1754 |
} |
|---|
| 1755 |
|
|---|
| 1756 |
/* Policy configurations for genearting target methods. */ |
|---|
| 1757 |
template MethodGeneratingPolicy() |
|---|
| 1758 |
{ |
|---|
| 1759 |
mixin CommonGeneratingPolicy; |
|---|
| 1760 |
|
|---|
| 1761 |
/* Geneartes method body. */ |
|---|
| 1762 |
string generateFunctionBody(func.../+[BUG 4217]+/)() @property |
|---|
| 1763 |
{ |
|---|
| 1764 |
return generateMethodBody!(Base, func); // given |
|---|
| 1765 |
} |
|---|
| 1766 |
} |
|---|
| 1767 |
|
|---|
| 1768 |
|
|---|
| 1769 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1770 |
// Generated code |
|---|
| 1771 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1772 |
|
|---|
| 1773 |
alias MemberFunctionGenerator!( ConstructorGeneratingPolicy!() ) |
|---|
| 1774 |
ConstructorGenerator; |
|---|
| 1775 |
alias MemberFunctionGenerator!( MethodGeneratingPolicy!() ) |
|---|
| 1776 |
MethodGenerator; |
|---|
| 1777 |
|
|---|
| 1778 |
public enum string code = |
|---|
| 1779 |
ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~ |
|---|
| 1780 |
MethodGenerator.generateCode!(targetOverloadSets); |
|---|
| 1781 |
|
|---|
| 1782 |
debug (SHOW_GENERATED_CODE) |
|---|
| 1783 |
{ |
|---|
| 1784 |
pragma(msg, "-------------------- < ", Base, " >"); |
|---|
| 1785 |
pragma(msg, code); |
|---|
| 1786 |
pragma(msg, "--------------------"); |
|---|
| 1787 |
} |
|---|
| 1788 |
} |
|---|
| 1789 |
|
|---|
| 1790 |
//debug = SHOW_GENERATED_CODE; |
|---|
| 1791 |
unittest |
|---|
| 1792 |
{ |
|---|
| 1793 |
// no function to implement |
|---|
| 1794 |
{ |
|---|
| 1795 |
interface I_1 {} |
|---|
| 1796 |
auto o = new BlackHole!I_1; |
|---|
| 1797 |
} |
|---|
| 1798 |
// parameters |
|---|
| 1799 |
{ |
|---|
| 1800 |
interface I_3 { void test(int, in int, out int, ref int, lazy int); } |
|---|
| 1801 |
auto o = new BlackHole!I_3; |
|---|
| 1802 |
} |
|---|
| 1803 |
// use of user-defined type |
|---|
| 1804 |
{ |
|---|
| 1805 |
struct S {} |
|---|
| 1806 |
interface I_4 { S test(); } |
|---|
| 1807 |
auto o = new BlackHole!I_4; |
|---|
| 1808 |
} |
|---|
| 1809 |
// overloads |
|---|
| 1810 |
{ |
|---|
| 1811 |
interface I_5 |
|---|
| 1812 |
{ |
|---|
| 1813 |
void test(string); |
|---|
| 1814 |
real test(real); |
|---|
| 1815 |
int test(); |
|---|
| 1816 |
int test() @property; // ? |
|---|
| 1817 |
} |
|---|
| 1818 |
auto o = new BlackHole!I_5; |
|---|
| 1819 |
} |
|---|
| 1820 |
// constructor forwarding |
|---|
| 1821 |
{ |
|---|
| 1822 |
static class C_6 |
|---|
| 1823 |
{ |
|---|
| 1824 |
this(int n) { assert(n == 42); } |
|---|
| 1825 |
this(string s) { assert(s == "Deeee"); } |
|---|
| 1826 |
this(...) {} |
|---|
| 1827 |
} |
|---|
| 1828 |
auto o1 = new BlackHole!C_6(42); |
|---|
| 1829 |
auto o2 = new BlackHole!C_6("Deeee"); |
|---|
| 1830 |
auto o3 = new BlackHole!C_6(1, 2, 3, 4); |
|---|
| 1831 |
} |
|---|
| 1832 |
// attributes |
|---|
| 1833 |
{ |
|---|
| 1834 |
interface I_7 |
|---|
| 1835 |
{ |
|---|
| 1836 |
ref int test_ref(); |
|---|
| 1837 |
int test_pure() pure; |
|---|
| 1838 |
int test_nothrow() nothrow; |
|---|
| 1839 |
int test_property() @property; |
|---|
| 1840 |
int test_safe() @safe; |
|---|
| 1841 |
int test_trusted() @trusted; |
|---|
| 1842 |
int test_system() @system; |
|---|
| 1843 |
int test_pure_nothrow() pure nothrow; |
|---|
| 1844 |
} |
|---|
| 1845 |
auto o = new BlackHole!I_7; |
|---|
| 1846 |
} |
|---|
| 1847 |
// storage classes |
|---|
| 1848 |
{ |
|---|
| 1849 |
interface I_8 |
|---|
| 1850 |
{ |
|---|
| 1851 |
void test_const() const; |
|---|
| 1852 |
void test_immutable() immutable; |
|---|
| 1853 |
void test_shared() shared; |
|---|
| 1854 |
void test_shared_const() shared const; |
|---|
| 1855 |
} |
|---|
| 1856 |
auto o = new BlackHole!I_8; |
|---|
| 1857 |
} |
|---|
| 1858 |
/+ // deep inheritance |
|---|
| 1859 |
{ |
|---|
| 1860 |
// XXX [BUG 2525,3525] |
|---|
| 1861 |
// NOTE: [r494] func.c(504-571) FuncDeclaration::semantic() |
|---|
| 1862 |
interface I { void foo(); } |
|---|
| 1863 |
interface J : I {} |
|---|
| 1864 |
interface K : J {} |
|---|
| 1865 |
static abstract class C_9 : K {} |
|---|
| 1866 |
auto o = new BlackHole!C_9; |
|---|
| 1867 |
}+/ |
|---|
| 1868 |
} |
|---|
| 1869 |
|
|---|
| 1870 |
|
|---|
| 1871 |
/* |
|---|
| 1872 |
Used by MemberFunctionGenerator. |
|---|
| 1873 |
*/ |
|---|
| 1874 |
package template OverloadSet(string nam, T...) |
|---|
| 1875 |
{ |
|---|
| 1876 |
enum string name = nam; |
|---|
| 1877 |
alias T contents; |
|---|
| 1878 |
} |
|---|
| 1879 |
|
|---|
| 1880 |
/* |
|---|
| 1881 |
Used by MemberFunctionGenerator. |
|---|
| 1882 |
*/ |
|---|
| 1883 |
package template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func)) |
|---|
| 1884 |
{ |
|---|
| 1885 |
alias ReturnType!(T) RT; |
|---|
| 1886 |
alias ParameterTypeTuple!(T) PT; |
|---|
| 1887 |
} |
|---|
| 1888 |
package template FuncInfo(Func) |
|---|
| 1889 |
{ |
|---|
| 1890 |
alias ReturnType!(Func) RT; |
|---|
| 1891 |
alias ParameterTypeTuple!(Func) PT; |
|---|
| 1892 |
} |
|---|
| 1893 |
|
|---|
| 1894 |
/* |
|---|
| 1895 |
General-purpose member function generator. |
|---|
| 1896 |
-------------------- |
|---|
| 1897 |
template GeneratingPolicy() |
|---|
| 1898 |
{ |
|---|
| 1899 |
// [optional] the name of the class where functions are derived |
|---|
| 1900 |
enum string BASE_CLASS_ID; |
|---|
| 1901 |
|
|---|
| 1902 |
// [optional] define this if you have only function types |
|---|
| 1903 |
enum bool WITHOUT_SYMBOL; |
|---|
| 1904 |
|
|---|
| 1905 |
// [optional] Returns preferred identifier for i-th parameter. |
|---|
| 1906 |
template PARAMETER_VARIABLE_ID(size_t i); |
|---|
| 1907 |
|
|---|
| 1908 |
// Returns the identifier of the FuncInfo instance for the i-th overload |
|---|
| 1909 |
// of the specified name. The identifier must be accessible in the scope |
|---|
| 1910 |
// where generated code is mixed. |
|---|
| 1911 |
template FUNCINFO_ID(string name, size_t i); |
|---|
| 1912 |
|
|---|
| 1913 |
// Returns implemented function body as a string. When WITHOUT_SYMBOL is |
|---|
| 1914 |
// defined, the latter is used. |
|---|
| 1915 |
template generateFunctionBody(alias func); |
|---|
| 1916 |
template generateFunctionBody(string name, FuncType); |
|---|
| 1917 |
} |
|---|
| 1918 |
-------------------- |
|---|
| 1919 |
*/ |
|---|
| 1920 |
package template MemberFunctionGenerator(alias Policy) |
|---|
| 1921 |
{ |
|---|
| 1922 |
private static: |
|---|
| 1923 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1924 |
// Internal stuffs |
|---|
| 1925 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1926 |
|
|---|
| 1927 |
enum CONSTRUCTOR_NAME = "__ctor"; |
|---|
| 1928 |
|
|---|
| 1929 |
// true if functions are derived from a base class |
|---|
| 1930 |
enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID"); |
|---|
| 1931 |
|
|---|
| 1932 |
// true if functions are specified as types, not symbols |
|---|
| 1933 |
enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL"); |
|---|
| 1934 |
|
|---|
| 1935 |
// preferred identifier for i-th parameter variable |
|---|
| 1936 |
static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID")) |
|---|
| 1937 |
{ |
|---|
| 1938 |
alias Policy.PARAMETER_VARIABLE_ID PARAMETER_VARIABLE_ID; |
|---|
| 1939 |
} |
|---|
| 1940 |
else |
|---|
| 1941 |
{ |
|---|
| 1942 |
template PARAMETER_VARIABLE_ID(size_t i) |
|---|
| 1943 |
{ |
|---|
| 1944 |
enum string PARAMETER_VARIABLE_ID = "a" ~ toStringNow!(i); |
|---|
| 1945 |
// default: a0, a1, ... |
|---|
| 1946 |
} |
|---|
| 1947 |
} |
|---|
| 1948 |
|
|---|
| 1949 |
// Returns a tuple consisting of 0,1,2,...,n-1. For static foreach. |
|---|
| 1950 |
template CountUp(size_t n) |
|---|
| 1951 |
{ |
|---|
| 1952 |
static if (n > 0) |
|---|
| 1953 |
alias TypeTuple!(CountUp!(n - 1), n - 1) CountUp; |
|---|
| 1954 |
else |
|---|
| 1955 |
alias TypeTuple!() CountUp; |
|---|
| 1956 |
} |
|---|
| 1957 |
|
|---|
| 1958 |
|
|---|
| 1959 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1960 |
// Code generator |
|---|
| 1961 |
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| 1962 |
|
|---|
| 1963 |
/* |
|---|
| 1964 |
* Runs through all the target overload sets and generates D code which |
|---|
| 1965 |
* implements all the functions in the overload sets. |
|---|
| 1966 |
*/ |
|---|
| 1967 |
public string generateCode(overloads...)() @property |
|---|
| 1968 |
{ |
|---|
| 1969 |
string code = ""; |
|---|
| 1970 |
|
|---|
| 1971 |
// run through all the overload sets |
|---|
| 1972 |
foreach (i_; CountUp!(0 + overloads.length)) // workaround |
|---|
| 1973 |
{ |
|---|
| 1974 |
enum i = 0 + i_; // workaround |
|---|
| 1975 |
alias overloads[i] oset; |
|---|
| 1976 |
|
|---|
| 1977 |
code ~= generateCodeForOverloadSet!(oset); |
|---|
| 1978 |
|
|---|
| 1979 |
static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME) |
|---|
| 1980 |
{ |
|---|
| 1981 |
// The generated function declarations may hide existing ones |
|---|
| 1982 |
// in the base class (cf. HiddenFuncError), so we put an alias |
|---|
| 1983 |
// declaration here to reveal possible hidden functions. |
|---|
| 1984 |
code ~= Format!("alias %s.%s %s;\n", |
|---|
| 1985 |
Policy.BASE_CLASS_ID, // [BUG 2540] super. |
|---|
| 1986 |
oset.name, oset.name ); |
|---|
| 1987 |
} |
|---|
| 1988 |
} |
|---|
| 1989 |
return code; |
|---|
| 1990 |
} |
|---|
| 1991 |
|
|---|
| 1992 |
// handle each overload set |
|---|
| 1993 |
private string generateCodeForOverloadSet(alias oset)() @property |
|---|
| 1994 |
{ |
|---|
| 1995 |
string code = ""; |
|---|
| 1996 |
|
|---|
| 1997 |
foreach (i_; CountUp!(0 + oset.contents.length)) // workaround |
|---|
| 1998 |
{ |
|---|
| 1999 |
enum i = 0 + i_; // workaround |
|---|
| 2000 |
code ~= generateFunction!( |
|---|
| 2001 |
Policy.FUNCINFO_ID!(oset.name, i), oset.name, |
|---|
| 2002 |
oset.contents[i]) ~ "\n"; |
|---|
| 2003 |
} |
|---|
| 2004 |
return code; |
|---|
| 2005 |
} |
|---|
| 2006 |
|
|---|
| 2007 |
/* |
|---|
| 2008 |
* Returns D code which implements the function func. This function |
|---|
| 2009 |
* actually generates only the declarator part; the function body part is |
|---|
| 2010 |
* generated by the functionGenerator() policy. |
|---|
| 2011 |
*/ |
|---|
| 2012 |
public string generateFunction( |
|---|
| 2013 |
string myFuncInfo, string name, func... )() @property |
|---|
| 2014 |
{ |
|---|
| 2015 |
enum isCtor = (name == CONSTRUCTOR_NAME); |
|---|
| 2016 |
|
|---|
| 2017 |
string code; // the result |
|---|
| 2018 |
|
|---|
| 2019 |
/*** Function Declarator ***/ |
|---|
| 2020 |
{ |
|---|
| 2021 |
alias FunctionTypeOf!(func) Func; |
|---|
| 2022 |
alias FunctionAttribute FA; |
|---|
| 2023 |
enum atts = functionAttributes!(func); |
|---|
| 2024 |
enum realName = isCtor ? "this" : name; |
|---|
| 2025 |
|
|---|
| 2026 |
/* Made them CTFE funcs just for the sake of Format!(...) */ |
|---|
| 2027 |
|
|---|
| 2028 |
// return type with optional "ref" |
|---|
| 2029 |
static string make_returnType() |
|---|
| 2030 |
{ |
|---|
| 2031 |
string rtype = ""; |
|---|
| 2032 |
|
|---|
| 2033 |
if (!isCtor) |
|---|
| 2034 |
{ |
|---|
| 2035 |
if (atts & FA.REF) rtype ~= "ref "; |
|---|
| 2036 |
rtype ~= myFuncInfo ~ ".RT"; |
|---|
| 2037 |
} |
|---|
| 2038 |
return rtype; |
|---|
| 2039 |
} |
|---|
| 2040 |
enum returnType = make_returnType(); |
|---|
| 2041 |
|
|---|
| 2042 |
// function attributes attached after declaration |
|---|
| 2043 |
static string make_postAtts() |
|---|
| 2044 |
{ |
|---|
| 2045 |
string poatts = ""; |
|---|
| 2046 |
if (atts & FA.PURE ) poatts ~= " pure"; |
|---|
| 2047 |
if (atts & FA.NOTHROW ) poatts ~= " nothrow"; |
|---|
| 2048 |
if (atts & FA.PROPERTY) poatts ~= " @property"; |
|---|
| 2049 |
if (atts & FA.SAFE ) poatts ~= " @safe"; |
|---|
| 2050 |
if (atts & FA.TRUSTED ) poatts ~= " @trusted"; |
|---|
| 2051 |
return poatts; |
|---|
| 2052 |
} |
|---|
| 2053 |
enum postAtts = make_postAtts(); |
|---|
| 2054 |
|
|---|
| 2055 |
// function storage class |
|---|
| 2056 |
static string make_storageClass() |
|---|
| 2057 |
{ |
|---|
| 2058 |
string postc = ""; |
|---|
| 2059 |
if (is(Func == shared)) postc ~= " shared"; |
|---|
| 2060 |
if (is(Func == const)) postc ~= " const"; |
|---|
| 2061 |
if (is(Func == immutable)) postc ~= " immutable"; |
|---|
| 2062 |
return postc; |
|---|
| 2063 |
} |
|---|
| 2064 |
enum storageClass = make_storageClass(); |
|---|
| 2065 |
|
|---|
| 2066 |
// |
|---|
| 2067 |
code ~= Format!("extern(%s) %s %s(%s) %s %s\n", |
|---|
| 2068 |
functionLinkage!(func), |
|---|
| 2069 |
returnType, |
|---|
| 2070 |
realName, |
|---|
| 2071 |
""~generateParameters!(myFuncInfo, func), |
|---|
| 2072 |
postAtts, storageClass ); |
|---|
| 2073 |
} |
|---|
| 2074 |
|
|---|
| 2075 |
/*** Function Body ***/ |
|---|
| 2076 |
code ~= "{\n"; |
|---|
| 2077 |
{ |
|---|
| 2078 |
enum nparams = ParameterTypeTuple!(func).length; |
|---|
| 2079 |
|
|---|
| 2080 |
/* Declare keywords: args, self and parent. */ |
|---|
| 2081 |
string preamble; |
|---|
| 2082 |
|
|---|
| 2083 |
preamble ~= "alias TypeTuple!(" ~ enumerateParameters!(nparams) ~ ") args;\n"; |
|---|
| 2084 |
if (!isCtor) |
|---|
| 2085 |
{ |
|---|
| 2086 |
preamble ~= "alias " ~ name ~ " self;\n"; |
|---|
| 2087 |
if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func)) |
|---|
| 2088 |
//preamble ~= "alias super." ~ name ~ " parent;\n"; // [BUG 2540] |
|---|
| 2089 |
preamble ~= "auto parent = &super." ~ name ~ ";\n"; |
|---|
| 2090 |
} |
|---|
| 2091 |
|
|---|
| 2092 |
// Function body |
|---|
| 2093 |
static if (WITHOUT_SYMBOL) |
|---|
| 2094 |
enum fbody = Policy.generateFunctionBody!(name, func); |
|---|
| 2095 |
else |
|---|
| 2096 |
enum fbody = Policy.generateFunctionBody!(func); |
|---|
| 2097 |
|
|---|
| 2098 |
code ~= preamble; |
|---|
| 2099 |
code ~= fbody; |
|---|
| 2100 |
} |
|---|
| 2101 |
code ~= "}"; |
|---|
| 2102 |
|
|---|
| 2103 |
return code; |
|---|
| 2104 |
} |
|---|
| 2105 |
|
|---|
| 2106 |
/* |
|---|
| 2107 |
* Returns D code which declares function parameters. |
|---|
| 2108 |
* "ref int a0, real a1, ..." |
|---|
| 2109 |
*/ |
|---|
| 2110 |
private string generateParameters(string myFuncInfo, func...)() @property |
|---|
| 2111 |
{ |
|---|
| 2112 |
alias ParameterStorageClass STC; |
|---|
| 2113 |
alias ParameterStorageClassTuple!(func) stcs; |
|---|
| 2114 |
enum nparams = stcs.length; |
|---|
| 2115 |
|
|---|
| 2116 |
string params = ""; // the result |
|---|
| 2117 |
|
|---|
| 2118 |
foreach (i, stc; stcs) |
|---|
| 2119 |
{ |
|---|
| 2120 |
if (i > 0) params ~= ", "; |
|---|
| 2121 |
|
|---|
| 2122 |
// Parameter storage classes. |
|---|
| 2123 |
if (stc & STC.SCOPE) params ~= "scope "; |
|---|
| 2124 |
if (stc & STC.OUT ) params ~= "out "; |
|---|
| 2125 |
if (stc & STC.REF ) params ~= "ref "; |
|---|
| 2126 |
if (stc & STC.LAZY ) params ~= "lazy "; |
|---|
| 2127 |
|
|---|
| 2128 |
// Take parameter type from the FuncInfo. |
|---|
| 2129 |
params ~= myFuncInfo ~ ".PT[" ~ toStringNow!(i) ~ "]"; |
|---|
| 2130 |
|
|---|
| 2131 |
// Declare a parameter variable. |
|---|
| 2132 |
params ~= " " ~ PARAMETER_VARIABLE_ID!(i); |
|---|
| 2133 |
} |
|---|
| 2134 |
|
|---|
| 2135 |
// Add some ellipsis part if needed. |
|---|
| 2136 |
final switch (variadicFunctionStyle!(func)) |
|---|
| 2137 |
{ |
|---|
| 2138 |
case Variadic.NO: |
|---|
| 2139 |
break; |
|---|
| 2140 |
|
|---|
| 2141 |
case Variadic.C, Variadic.D: |
|---|
| 2142 |
// (...) or (a, b, ...) |
|---|
| 2143 |
params ~= (nparams == 0) ? "..." : ", ..."; |
|---|
| 2144 |
break; |
|---|
| 2145 |
|
|---|
| 2146 |
case Variadic.TYPESAFE: |
|---|
| 2147 |
params ~= " ..."; |
|---|
| 2148 |
break; |
|---|
| 2149 |
} |
|---|
| 2150 |
|
|---|
| 2151 |
return params; |
|---|
| 2152 |
} |
|---|
| 2153 |
|
|---|
| 2154 |
// Returns D code which enumerates n parameter variables using comma as the |
|---|
| 2155 |
// separator. "a0, a1, a2, a3" |
|---|
| 2156 |
private string enumerateParameters(size_t n)() @property |
|---|
| 2157 |
{ |
|---|
| 2158 |
string params = ""; |
|---|
| 2159 |
|
|---|
| 2160 |
foreach (i_; CountUp!(n)) |
|---|
| 2161 |
{ |
|---|
| 2162 |
enum i = 0 + i_; // workaround |
|---|
| 2163 |
if (i > 0) params ~= ", "; |
|---|
| 2164 |
params ~= PARAMETER_VARIABLE_ID!(i); |
|---|
| 2165 |
} |
|---|
| 2166 |
return params; |
|---|
| 2167 |
} |
|---|
| 2168 |
} |
|---|
| 2169 |
|
|---|
| 2170 |
|
|---|
| 2171 |
/** |
|---|
| 2172 |
Predefined how-policies for $(D AutoImplement). These templates are used by |
|---|
| 2173 |
$(D BlackHole) and $(D WhiteHole), respectively. |
|---|
| 2174 |
*/ |
|---|
| 2175 |
template generateEmptyFunction(C, func.../+[BUG 4217]+/) |
|---|
| 2176 |
{ |
|---|
| 2177 |
static if (is(ReturnType!(func) == void)) |
|---|
| 2178 |
enum string generateEmptyFunction = q{ |
|---|
| 2179 |
}; |
|---|
| 2180 |
else static if (functionAttributes!(func) & FunctionAttribute.REF) |
|---|
| 2181 |
enum string generateEmptyFunction = q{ |
|---|
| 2182 |
static typeof(return) dummy; |
|---|
| 2183 |
return dummy; |
|---|
| 2184 |
}; |
|---|
| 2185 |
else |
|---|
| 2186 |
enum string generateEmptyFunction = q{ |
|---|
| 2187 |
return typeof(return).init; |
|---|
| 2188 |
}; |
|---|
| 2189 |
} |
|---|
| 2190 |
|
|---|
| 2191 |
/// ditto |
|---|
| 2192 |
template generateAssertTrap(C, func.../+[BUG 4217]+/) |
|---|
| 2193 |
{ |
|---|
| 2194 |
static if (functionAttributes!(func) & FunctionAttribute.NOTHROW) //XXX |
|---|
| 2195 |
{ |
|---|
| 2196 |
pragma(msg, "Warning: WhiteHole!(", C, ") used assert(0) instead " |
|---|
| 2197 |
"of Error for the auto-implemented nothrow function ", |
|---|
| 2198 |
C, ".", __traits(identifier, func)); |
|---|
| 2199 |
enum string generateAssertTrap = |
|---|
| 2200 |
`assert(0, "` ~ C.stringof ~ "." ~ __traits(identifier, func) |
|---|
| 2201 |
~ ` is not implemented");`; |
|---|
| 2202 |
} |
|---|
| 2203 |
else |
|---|
| 2204 |
enum string generateAssertTrap = |
|---|
| 2205 |
`throw new NotImplementedError("` ~ C.stringof ~ "." |
|---|
| 2206 |
~ __traits(identifier, func) ~ `");`; |
|---|
| 2207 |
} |
|---|
| 2208 |
|
|---|
| 2209 |
/** |
|---|
| 2210 |
Options regarding auto-initialization of a $(D RefCounted) object (see |
|---|
| 2211 |
the definition of $(D RefCounted) below). |
|---|
| 2212 |
*/ |
|---|
| 2213 |
enum RefCountedAutoInitialize |
|---|
| 2214 |
{ |
|---|
| 2215 |
/// Do not auto-initialize the object |
|---|
| 2216 |
no, |
|---|
| 2217 |
/// Auto-initialize the object |
|---|
| 2218 |
yes, |
|---|
| 2219 |
} |
|---|
| 2220 |
|
|---|
| 2221 |
/** |
|---|
| 2222 |
Defines a reference-counted object containing a $(D T) value as |
|---|
| 2223 |
payload. $(D RefCounted) keeps track of all references of an object, |
|---|
| 2224 |
and when the reference count goes down to zero, frees the underlying |
|---|
| 2225 |
store. $(D RefCounted) uses $(D malloc) and $(D free) for operation. |
|---|
| 2226 |
|
|---|
| 2227 |
$(D RefCounted) is unsafe and should be used with care. No references |
|---|
| 2228 |
to the payload should be escaped outside the $(D RefCounted) object. |
|---|
| 2229 |
|
|---|
| 2230 |
The $(D autoInit) option makes the object ensure the store is |
|---|
| 2231 |
automatically initialized. Leaving $(D autoInit == |
|---|
| 2232 |
RefCountedAutoInitialize.yes) (the default option) is convenient but |
|---|
| 2233 |
has the cost of a test whenever the payload is accessed. If $(D |
|---|
| 2234 |
autoInit == RefCountedAutoInitialize.no), user code must call either |
|---|
| 2235 |
$(D refCountedIsInitialized) or $(D refCountedEnsureInitialized) |
|---|
| 2236 |
before attempting to access the payload. Not doing so results in null |
|---|
| 2237 |
pointer dereference. |
|---|
| 2238 |
|
|---|
| 2239 |
Example: |
|---|
| 2240 |
---- |
|---|
| 2241 |
// A pair of an $(D int) and a $(D size_t) - the latter being the |
|---|
| 2242 |
// reference count - will be dynamically allocated |
|---|
| 2243 |
auto rc1 = RefCounted!int(5); |
|---|
| 2244 |
assert(rc1 == 5); |
|---|
| 2245 |
// No more allocation, add just one extra reference count |
|---|
| 2246 |
auto rc2 = rc1; |
|---|
| 2247 |
// Reference semantics |
|---|
| 2248 |
rc2 = 42; |
|---|
| 2249 |
assert(rc1 == 42); |
|---|
| 2250 |
// the pair will be freed when rc1 and rc2 go out of scope |
|---|
| 2251 |
---- |
|---|
| 2252 |
*/ |
|---|
| 2253 |
struct RefCounted(T, RefCountedAutoInitialize autoInit = |
|---|
| 2254 |
RefCountedAutoInitialize.yes) |
|---|
| 2255 |
if (!is(T == class)) |
|---|
| 2256 |
{ |
|---|
| 2257 |
struct _RefCounted |
|---|
| 2258 |
{ |
|---|
| 2259 |
private Tuple!(T, "_payload", size_t, "_count") * _store; |
|---|
| 2260 |
debug(RefCounted) |
|---|
| 2261 |
{ |
|---|
| 2262 |
private bool _debugging = false; |
|---|
| 2263 |
@property bool debugging() const |
|---|
| 2264 |
{ |
|---|
| 2265 |
return _debugging; |
|---|
| 2266 |
} |
|---|
| 2267 |
@property void debugging(bool d) |
|---|
| 2268 |
{ |
|---|
| 2269 |
if (d != _debugging) |
|---|
| 2270 |
{ |
|---|
| 2271 |
writeln(typeof(this).stringof, "@", |
|---|
| 2272 |
cast(void*) _store, |
|---|
| 2273 |
d ? ": starting debug" : ": ending debug"); |
|---|
| 2274 |
} |
|---|
| 2275 |
_debugging = d; |
|---|
| 2276 |
} |
|---|
| 2277 |
} |
|---|
| 2278 |
|
|---|
| 2279 |
private void initialize(A...)(A args) |
|---|
| 2280 |
{ |
|---|
| 2281 |
const sz = (*_store).sizeof; |
|---|
| 2282 |
auto p = malloc(sz)[0 .. sz]; |
|---|
| 2283 |
if (sz >= size_t.sizeof && p.ptr) |
|---|
| 2284 |
{ |
|---|
| 2285 |
GC.addRange(p.ptr, sz); |
|---|
| 2286 |
} |
|---|
| 2287 |
emplace!T(p[0 .. T.sizeof], args); |
|---|
| 2288 |
_store = cast(typeof(_store)) p.ptr; |
|---|
| 2289 |
_store._count = 1; |
|---|
| 2290 |
debug(RefCounted) if (debugging) writeln(typeof(this).stringof, |
|---|
| 2291 |
"@", cast(void*) _store, ": initialized with ", |
|---|
| 2292 |
A.stringof); |
|---|
| 2293 |
} |
|---|
| 2294 |
|
|---|
| 2295 |
/** |
|---|
| 2296 |
Returns $(D true) if and only if the underlying store has been |
|---|
| 2297 |
allocated and initialized. |
|---|
| 2298 |
*/ |
|---|
| 2299 |
@property bool isInitialized() const |
|---|
| 2300 |
{ |
|---|
| 2301 |
return _store !is null; |
|---|
| 2302 |
} |
|---|
| 2303 |
|
|---|
| 2304 |
/** |
|---|
| 2305 |
Makes sure the payload was properly initialized. Such a |
|---|
| 2306 |
call is typically inserted before using the payload. |
|---|
| 2307 |
*/ |
|---|
| 2308 |
void ensureInitialized() |
|---|
| 2309 |
{ |
|---|
| 2310 |
if (!isInitialized) initialize(); |
|---|
| 2311 |
} |
|---|
| 2312 |
|
|---|
| 2313 |
} |
|---|
| 2314 |
_RefCounted RefCounted; |
|---|
| 2315 |
|
|---|
| 2316 |
/** |
|---|
| 2317 |
Constructor that initializes the payload. |
|---|
| 2318 |
|
|---|
| 2319 |
Postcondition: $(D refCountedIsInitialized) |
|---|
| 2320 |
*/ |
|---|
| 2321 |
this(A...)(A args) if (A.length > 0) |
|---|
| 2322 |
{ |
|---|
| 2323 |
RefCounted.initialize(args); |
|---|
| 2324 |
} |
|---|
| 2325 |
|
|---|
| 2326 |
/** |
|---|
| 2327 |
Constructor that tracks the reference count appropriately. If $(D |
|---|
| 2328 |
!refCountedIsInitialized), does nothing. |
|---|
| 2329 |
*/ |
|---|
| 2330 |
this(this) |
|---|
| 2331 |
{ |
|---|
| 2332 |
if (!RefCounted.isInitialized) return; |
|---|
| 2333 |
++RefCounted._store._count; |
|---|
| 2334 |
debug(RefCounted) if (RefCounted.debugging) |
|---|
| 2335 |
writeln(typeof(this).stringof, |
|---|
| 2336 |
"@", cast(void*) RefCounted._store, ": bumped refcount to ", |
|---|
| 2337 |
RefCounted._store._count); |
|---|
| 2338 |
} |
|---|
| 2339 |
|
|---|
| 2340 |
/** |
|---|
| 2341 |
Destructor that tracks the reference count appropriately. If $(D |
|---|
| 2342 |
!refCountedIsInitialized), does nothing. When the reference count goes |
|---|
| 2343 |
down to zero, calls $(D clear) agaist the payload and calls $(D free) |
|---|
| 2344 |
to deallocate the corresponding resource. |
|---|
| 2345 |
*/ |
|---|
| 2346 |
~this() |
|---|
| 2347 |
{ |
|---|
| 2348 |
if (!RefCounted._store) return; |
|---|
| 2349 |
assert(RefCounted._store._count > 0); |
|---|
| 2350 |
if (--RefCounted._store._count) |
|---|
| 2351 |
{ |
|---|
| 2352 |
debug(RefCounted) if (RefCounted.debugging) |
|---|
| 2353 |
writeln(typeof(this).stringof, |
|---|
| 2354 |
"@", cast(void*)RefCounted._store, |
|---|
| 2355 |
": decrement refcount to ", RefCounted._store._count); |
|---|
| 2356 |
return; |
|---|
| 2357 |
} |
|---|
| 2358 |
debug(RefCounted) if (RefCounted.debugging) |
|---|
| 2359 |
{ |
|---|
| 2360 |
write(typeof(this).stringof, |
|---|
| 2361 |
"@", cast(void*)RefCounted._store, ": freeing... "); |
|---|
| 2362 |
stdout.flush(); |
|---|
| 2363 |
} |
|---|
| 2364 |
// Done, deallocate |
|---|
| 2365 |
assert(RefCounted._store); |
|---|
| 2366 |
clear(RefCounted._store._payload); |
|---|
| 2367 |
if (hasIndirections!T && RefCounted._store) |
|---|
| 2368 |
GC.removeRange(RefCounted._store); |
|---|
| 2369 |
free(RefCounted._store); |
|---|
| 2370 |
RefCounted._store = null; |
|---|
| 2371 |
debug(RefCounted) if (RefCounted.debugging) writeln("done!"); |
|---|
| 2372 |
} |
|---|
| 2373 |
|
|---|
| 2374 |
/** |
|---|
| 2375 |
Assignment operators |
|---|
| 2376 |
*/ |
|---|
| 2377 |
void opAssign(typeof(this) rhs) |
|---|
| 2378 |
{ |
|---|
| 2379 |
swap(RefCounted._store, rhs.RefCounted._store); |
|---|
| 2380 |
} |
|---|
| 2381 |
|
|---|
| 2382 |
/// Ditto |
|---|
| 2383 |
void opAssign(T rhs) |
|---|
| 2384 |
{ |
|---|
| 2385 |
RefCounted._store._payload = move(rhs); |
|---|
| 2386 |
} |
|---|
| 2387 |
|
|---|
| 2388 |
/** |
|---|
| 2389 |
Returns a reference to the payload. If (autoInit == |
|---|
| 2390 |
RefCountedAutoInitialize.yes), calls $(D |
|---|
| 2391 |
refCountedEnsureInitialized). Otherwise, just issues $(D |
|---|
| 2392 |
assert(refCountedIsInitialized)). |
|---|
| 2393 |
*/ |
|---|
| 2394 |
alias refCountedPayload this; |
|---|
| 2395 |
|
|---|
| 2396 |
/** |
|---|
| 2397 |
Returns a reference to the payload. If (autoInit == |
|---|
| 2398 |
RefCountedAutoInitialize.yes), calls $(D |
|---|
| 2399 |
refCountedEnsureInitialized). Otherwise, just issues $(D |
|---|
| 2400 |
assert(refCountedIsInitialized)). Used with $(D alias |
|---|
| 2401 |
refCountedPayload this;), so callers can just use the $(D RefCounted) |
|---|
| 2402 |
object as a $(D T). |
|---|
| 2403 |
*/ |
|---|
| 2404 |
@property ref T refCountedPayload() |
|---|
| 2405 |
{ |
|---|
| 2406 |
static if (autoInit == RefCountedAutoInitialize.yes) |
|---|
| 2407 |
{ |
|---|
| 2408 |
RefCounted.ensureInitialized(); |
|---|
| 2409 |
} |
|---|
| 2410 |
else |
|---|
| 2411 |
{ |
|---|
| 2412 |
assert(RefCounted.isInitialized); |
|---|
| 2413 |
} |
|---|
| 2414 |
return RefCounted._store._payload; |
|---|
| 2415 |
} |
|---|
| 2416 |
|
|---|
| 2417 |
// |
|---|
| 2418 |
@property ref const(T) refCountedPayload() const |
|---|
| 2419 |
{ |
|---|
| 2420 |
static if (autoInit == RefCountedAutoInitialize.yes) |
|---|
| 2421 |
{ |
|---|
| 2422 |
// @@@ |
|---|
| 2423 |
//refCountedEnsureInitialized(); |
|---|
| 2424 |
assert(RefCounted.isInitialized); |
|---|
| 2425 |
} |
|---|
| 2426 |
else |
|---|
| 2427 |
{ |
|---|
| 2428 |
assert(RefCounted.isInitialized); |
|---|
| 2429 |
} |
|---|
| 2430 |
return RefCounted._store._payload; |
|---|
| 2431 |
} |
|---|
| 2432 |
} |
|---|
| 2433 |
|
|---|
| 2434 |
unittest |
|---|
| 2435 |
{ |
|---|
| 2436 |
RefCounted!int* p; |
|---|
| 2437 |
{ |
|---|
| 2438 |
auto rc1 = RefCounted!int(5); |
|---|
| 2439 |
p = &rc1; |
|---|
| 2440 |
assert(rc1 == 5); |
|---|
| 2441 |
assert(rc1.RefCounted._store._count == 1); |
|---|
| 2442 |
auto rc2 = rc1; |
|---|
| 2443 |
assert(rc1.RefCounted._store._count == 2); |
|---|
| 2444 |
// Reference semantics |
|---|
| 2445 |
rc2 = 42; |
|---|
| 2446 |
assert(rc1 == 42); |
|---|
| 2447 |
rc2 = rc2; |
|---|
| 2448 |
assert(rc2.RefCounted._store._count == 2); |
|---|
| 2449 |
rc1 = rc2; |
|---|
| 2450 |
assert(rc1.RefCounted._store._count == 2); |
|---|
| 2451 |
} |
|---|
| 2452 |
assert(p.RefCounted._store == null); |
|---|
| 2453 |
|
|---|
| 2454 |
// RefCounted as a member |
|---|
| 2455 |
struct A |
|---|
| 2456 |
{ |
|---|
| 2457 |
RefCounted!int x; |
|---|
| 2458 |
this(int y) |
|---|
| 2459 |
{ |
|---|
| 2460 |
x.RefCounted.initialize(y); |
|---|
| 2461 |
} |
|---|
| 2462 |
A copy() |
|---|
| 2463 |
{ |
|---|
| 2464 |
auto another = this; |
|---|
| 2465 |
return another; |
|---|
| 2466 |
} |
|---|
| 2467 |
} |
|---|
| 2468 |
auto a = A(4); |
|---|
| 2469 |
auto b = a.copy(); |
|---|
| 2470 |
if (a.x.RefCounted._store._count != 2) { |
|---|
| 2471 |
stderr.writeln("*** BUG 4356 still unfixed"); |
|---|
| 2472 |
} |
|---|
| 2473 |
} |
|---|
| 2474 |
|
|---|
| 2475 |
/** |
|---|
| 2476 |
Allocates a $(D class) object right inside the current scope, |
|---|
| 2477 |
therefore avoiding the overhead of $(D new). This facility is unsafe; |
|---|
| 2478 |
it is the responsibility of the user to not escape a reference to the |
|---|
| 2479 |
object outside the scope. |
|---|
| 2480 |
|
|---|
| 2481 |
Example: |
|---|
| 2482 |
---- |
|---|
| 2483 |
unittest |
|---|
| 2484 |
{ |
|---|
| 2485 |
class A { int x; } |
|---|
| 2486 |
auto a1 = scoped!A(); |
|---|
| 2487 |
auto a2 = scoped!A(); |
|---|
| 2488 |
a1.x = 42; |
|---|
| 2489 |
a2.x = 53; |
|---|
| 2490 |
assert(a1.x == 42); |
|---|
| 2491 |
} |
|---|
| 2492 |
---- |
|---|
| 2493 |
*/ |
|---|
| 2494 |
@system auto scoped(T, Args...)(Args args) if (is(T == class)) |
|---|
| 2495 |
{ |
|---|
| 2496 |
static struct Scoped |
|---|
| 2497 |
{ |
|---|
| 2498 |
private ubyte[__traits(classInstanceSize, T)] Scoped_store = void; |
|---|
| 2499 |
@property T Scoped_payload() |
|---|
| 2500 |
{ |
|---|
| 2501 |
return cast(T) (Scoped_store.ptr); |
|---|
| 2502 |
} |
|---|
| 2503 |
alias Scoped_payload this; |
|---|
| 2504 |
|
|---|
| 2505 |
@disable this(this) |
|---|
| 2506 |
{ |
|---|
| 2507 |
writeln("Illegal call to Scoped this(this)"); |
|---|
| 2508 |
assert(false); |
|---|
| 2509 |
} |
|---|
| 2510 |
|
|---|
| 2511 |
~this() |
|---|
| 2512 |
{ |
|---|
| 2513 |
destroy(Scoped_payload); |
|---|
| 2514 |
if ((cast(void**) Scoped_store.ptr)[1]) // if monitor is not null |
|---|
| 2515 |
{ |
|---|
| 2516 |
_d_monitordelete(Scoped_payload, true); |
|---|
| 2517 |
} |
|---|
| 2518 |
} |
|---|
| 2519 |
} |
|---|
| 2520 |
|
|---|
| 2521 |
byte[__traits(classInstanceSize, T)] result; |
|---|
| 2522 |
static if (Args.length == 0) |
|---|
| 2523 |
{ |
|---|
| 2524 |
result[] = typeid(T).init[]; |
|---|
| 2525 |
static if (is(typeof(T.init.__ctor()))) |
|---|
| 2526 |
{ |
|---|
| 2527 |
(cast(T) result.ptr).__ctor(); |
|---|
| 2528 |
} |
|---|
| 2529 |
} |
|---|
| 2530 |
else |
|---|
| 2531 |
{ |
|---|
| 2532 |
emplace!T(cast(void[]) result, args); |
|---|
| 2533 |
} |
|---|
| 2534 |
return cast(Scoped) result; |
|---|
| 2535 |
} |
|---|
| 2536 |
|
|---|
| 2537 |
// Used by scoped() above |
|---|
| 2538 |
private extern (C) static void _d_monitordelete(Object h, bool det); |
|---|
| 2539 |
|
|---|
| 2540 |
/* |
|---|
| 2541 |
Used by scoped() above. Calls the destructors of an object |
|---|
| 2542 |
transitively up the inheritance path, but work properly only if the |
|---|
| 2543 |
static type of the object (T) is known. |
|---|
| 2544 |
*/ |
|---|
| 2545 |
private void destroy(T)(T obj) if (is(T == class)) |
|---|
| 2546 |
{ |
|---|
| 2547 |
static if (is(typeof(obj.__dtor()))) |
|---|
| 2548 |
{ |
|---|
| 2549 |
obj.__dtor(); |
|---|
| 2550 |
} |
|---|
| 2551 |
static if (!is(T == Object) && is(T Base == super)) |
|---|
| 2552 |
{ |
|---|
| 2553 |
Base b = obj; |
|---|
| 2554 |
destroy(b); |
|---|
| 2555 |
} |
|---|
| 2556 |
} |
|---|
| 2557 |
|
|---|
| 2558 |
unittest |
|---|
| 2559 |
{ |
|---|
| 2560 |
class A { int x = 1; } |
|---|
| 2561 |
auto a1 = scoped!A(); |
|---|
| 2562 |
assert(a1.x == 1); |
|---|
| 2563 |
auto a2 = scoped!A(); |
|---|
| 2564 |
a1.x = 42; |
|---|
| 2565 |
a2.x = 53; |
|---|
| 2566 |
assert(a1.x == 42); |
|---|
| 2567 |
} |
|---|
| 2568 |
|
|---|
| 2569 |
unittest |
|---|
| 2570 |
{ |
|---|
| 2571 |
class A { int x = 1; this() { x = 2; } } |
|---|
| 2572 |
auto a1 = scoped!A(); |
|---|
| 2573 |
assert(a1.x == 2); |
|---|
| 2574 |
auto a2 = scoped!A(); |
|---|
| 2575 |
a1.x = 42; |
|---|
| 2576 |
a2.x = 53; |
|---|
| 2577 |
assert(a1.x == 42); |
|---|
| 2578 |
} |
|---|
| 2579 |
|
|---|
| 2580 |
unittest |
|---|
| 2581 |
{ |
|---|
| 2582 |
class A { int x = 1; this(int y) { x = y; } ~this() {} } |
|---|
| 2583 |
auto a1 = scoped!A(5); |
|---|
| 2584 |
assert(a1.x == 5); |
|---|
| 2585 |
auto a2 = scoped!A(); |
|---|
| 2586 |
a1.x = 42; |
|---|
| 2587 |
a2.x = 53; |
|---|
| 2588 |
assert(a1.x == 42); |
|---|
| 2589 |
} |
|---|
| 2590 |
|
|---|
| 2591 |
unittest |
|---|
| 2592 |
{ |
|---|
| 2593 |
class A { static bool dead; ~this() { dead = true; } } |
|---|
| 2594 |
class B : A { static bool dead; ~this() { dead = true; } } |
|---|
| 2595 |
{ |
|---|
| 2596 |
auto b = scoped!B; |
|---|
| 2597 |
} |
|---|
| 2598 |
assert(B.dead, "asdasd"); |
|---|
| 2599 |
assert(A.dead, "asdasd"); |
|---|
| 2600 |
} |
|---|