mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 06:00:35 +03:00
std.math: minor change in approxEqual.
std.contracts: added functions pointsTo() std.numeric: minor unittest fixes. std.bitmanip: fixed code bloat issue, reintroduced FloatRep and DoubleRep. std.conv: minor simplification of implementation. std.regexp: added reference to ECMA standard in the documentation. std.getopt: changed return type from bool to void, error is signaled by use of exceptions. std.functional: added unaryFun, binaryFun, adjoin. std.string: updated documentation, changed code to compile with warnings enabled. std.traits: changed FieldTypeTuple; added RepresentationTypeTuple, hasAliasing; fixed bug 1826; added call to flush() from within write; fixed unlisted bug in lines(). std.algorithm: added map, reduce, filter, inPlace, move, swap, overwriteAdjacent, find, findRange, findBoyerMoore, findAdjacent, findAmong, findAmongSorted, canFind, canFindAmong, canFindAmongSorted, count, equal, overlap, min, max, mismatch, EditOp, none, substitute, insert, remove, levenshteinDistance, levenshteinDistanceAndPath, copy, copyIf, iterSwap, swapRanges, reverse, rotate, SwapStrategy, Unstable, Semistable, Stable, eliminate, partition, nthElement, sort, schwartzSort, partialSort, isSorted, makeIndex, schwartzMakeIndex, lowerBound, upperBound, equalRange, canFindSorted. std.thread: fixed so it compiles with warnings enabled. std.file: made getSize() faster under Linux. std.random: fixed so it compiles with warnings enabled; improved function uniform so it deduces type generated from its arguments. std.format: added fixes to make formatting work with const data. std.path: minor documentation changes.
This commit is contained in:
parent
0aea504e90
commit
29f3cc23f7
17 changed files with 3948 additions and 493 deletions
3275
std/algorithm.d
3275
std/algorithm.d
File diff suppressed because it is too large
Load diff
112
std/bitmanip.d
112
std/bitmanip.d
|
@ -1,10 +1,15 @@
|
|||
// Written in the D programming language
|
||||
|
||||
/**
|
||||
Bit-level manipulation facilities.
|
||||
Bit-level manipulation facilities.
|
||||
|
||||
Authors:
|
||||
|
||||
$(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
|
||||
Alexandrescu)
|
||||
|
||||
Macros:
|
||||
WIKI = StdBitarray
|
||||
Macros:
|
||||
WIKI = StdBitarray
|
||||
*/
|
||||
|
||||
module std.bitmanip;
|
||||
|
@ -12,28 +17,23 @@ module std.bitmanip;
|
|||
//debug = bitarray; // uncomment to turn on debugging printf's
|
||||
|
||||
private import std.intrinsic;
|
||||
private import std.metastrings;
|
||||
private import std.stdio;
|
||||
|
||||
private string myToString(ulong n)
|
||||
private template myToString(ulong n, string suffix = n > uint.max ? "UL" : "U")
|
||||
{
|
||||
return n < 10
|
||||
? "" ~ cast(char) (n + '0')
|
||||
: myToString(n / 10) ~ myToString(n % 10);
|
||||
static if (n < 10)
|
||||
enum myToString = cast(char) (n + '0') ~ suffix;
|
||||
else
|
||||
enum myToString = .myToString!(n / 10, "")
|
||||
~ .myToString!(n % 10, "") ~ suffix;
|
||||
}
|
||||
|
||||
private string toStringSfx(ulong n)
|
||||
{
|
||||
return myToString(n) ~ (n > uint.max ? "UL" : "U");
|
||||
}
|
||||
|
||||
private string createAccessors(
|
||||
string store, T, string name, size_t len, size_t offset)()
|
||||
private template createAccessors(
|
||||
string store, T, string name, size_t len, size_t offset)
|
||||
{
|
||||
static if (!name.length)
|
||||
{
|
||||
// No need to create any accessor
|
||||
return "";
|
||||
enum result = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -47,52 +47,49 @@ private string createAccessors(
|
|||
signBitCheck = 1uL << (len - 1),
|
||||
extendSign = ~((cast(MasksType)1u << len) - 1);
|
||||
|
||||
string result;
|
||||
static if (is(T == bool))
|
||||
{
|
||||
static assert(len == 1);
|
||||
enum result =
|
||||
// getter
|
||||
result ~= "bool " ~ name ~ "(){ return "
|
||||
"("~store~" & "~toStringSfx(maskAllElse)~") != 0;}\n";
|
||||
"bool " ~ name ~ "(){ return "
|
||||
~"("~store~" & "~myToString!(maskAllElse)~") != 0;}\n"
|
||||
// setter
|
||||
result ~= "void " ~ name ~ "(bool v){"
|
||||
"if (v) "~store~" |= "~toStringSfx(maskAllElse)~";"
|
||||
"else "~store~" &= "~toStringSfx(maskMyself)~";}\n";
|
||||
~"void " ~ name ~ "(bool v){"
|
||||
~"if (v) "~store~" |= "~myToString!(maskAllElse)~";"
|
||||
~"else "~store~" &= "~myToString!(maskMyself)~";}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
// getter
|
||||
result ~= T.stringof ~ " " ~ name ~ "(){ auto result = "
|
||||
enum result = T.stringof ~ " " ~ name ~ "(){ auto result = "
|
||||
"("~store~" & "
|
||||
~ toStringSfx(maskAllElse) ~ ") >>"
|
||||
~ toStringSfx(offset) ~ ";";
|
||||
static if (T.min < 0)
|
||||
{
|
||||
result ~= "if (result >= " ~ toStringSfx(signBitCheck)
|
||||
~ ") result |= " ~ toStringSfx(extendSign) ~ ";";
|
||||
}
|
||||
result ~= " return cast("~T.stringof~") result;}\n";
|
||||
~ myToString!(maskAllElse) ~ ") >>"
|
||||
~ myToString!(offset) ~ ";"
|
||||
~ (T.min < 0
|
||||
? "if (result >= " ~ myToString!(signBitCheck)
|
||||
~ ") result |= " ~ myToString!(extendSign) ~ ";"
|
||||
: "")
|
||||
~ " return cast("~T.stringof~") result;}\n"
|
||||
// setter
|
||||
result ~= "void " ~ name ~ "(" ~ T.stringof
|
||||
~ " v){ "~store~" = ("~store~" & "
|
||||
~ toStringSfx(maskMyself) ~ ") | "
|
||||
~ "((cast(typeof("~store~")) v << " ~ toStringSfx(offset)
|
||||
~ ") & " ~ toStringSfx(maskAllElse)
|
||||
~ ");}\n";
|
||||
~"void "~name~"("~T.stringof~" v){ "
|
||||
~store~" = cast(typeof("~store~"))"
|
||||
" (("~store~" & "~myToString!(maskMyself)~")"
|
||||
" | ((cast(typeof("~store~")) v << "~myToString!(offset)~")"
|
||||
" & "~myToString!(maskAllElse)~"));}\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private string createStoreName(Ts...)()
|
||||
private template createStoreName(Ts...)
|
||||
{
|
||||
static if (Ts.length == 0)
|
||||
return "";
|
||||
static if (Ts.length < 2)
|
||||
enum createStoreName = "";
|
||||
else
|
||||
return Ts[1] ~ createStoreName!(Ts[3 .. $])();
|
||||
enum createStoreName = Ts[1] ~ createStoreName!(Ts[3 .. $]);
|
||||
}
|
||||
|
||||
private string createFields(string store, size_t offset, Ts...)()
|
||||
private template createFields(string store, size_t offset, Ts...)
|
||||
{
|
||||
static if (!Ts.length)
|
||||
{
|
||||
|
@ -106,12 +103,13 @@ private string createFields(string store, size_t offset, Ts...)()
|
|||
alias ulong StoreType;
|
||||
else
|
||||
static assert(false, myToString(offset));
|
||||
return "private " ~ StoreType.stringof ~ " " ~ store ~ ";";
|
||||
enum result = "private " ~ StoreType.stringof ~ " " ~ store ~ ";";
|
||||
}
|
||||
else
|
||||
{
|
||||
return createAccessors!(store, Ts[0], Ts[1], Ts[2], offset)()
|
||||
~ createFields!(store, offset + Ts[2], Ts[3 .. $])();
|
||||
enum result
|
||||
= createAccessors!(store, Ts[0], Ts[1], Ts[2], offset).result
|
||||
~ createFields!(store, offset + Ts[2], Ts[3 .. $]).result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,11 +162,9 @@ bool), followed by unsigned types, followed by signed types.
|
|||
|
||||
template bitfields(T...)
|
||||
{
|
||||
enum string bitfields = createFields!(createStoreName!(T)(), 0, T)();
|
||||
enum { bitfields = createFields!(createStoreName!(T), 0, T).result }
|
||||
}
|
||||
|
||||
version(none)
|
||||
{
|
||||
/**
|
||||
Allows manipulating the fraction, exponent, and sign parts of a
|
||||
$(D_PARAM float) separately. The definition is:
|
||||
|
@ -258,7 +254,6 @@ unittest
|
|||
ubyte, "z", 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of bits.
|
||||
|
@ -305,7 +300,7 @@ struct BitArray
|
|||
/**********************************************
|
||||
* Support for [$(I index)] operation for BitArray.
|
||||
*/
|
||||
bool opIndex(size_t i)
|
||||
bool opIndex(size_t i) const
|
||||
in
|
||||
{
|
||||
assert(i < len);
|
||||
|
@ -315,6 +310,19 @@ struct BitArray
|
|||
return cast(bool)bt(ptr, i);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
void Fun(const BitArray arr)
|
||||
{
|
||||
auto x = arr[0];
|
||||
assert(x == 1);
|
||||
}
|
||||
BitArray a;
|
||||
a.length = 3;
|
||||
a[0] = 1;
|
||||
Fun(a);
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
bool opIndexAssign(bool b, size_t i)
|
||||
in
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* Author:
|
||||
*
|
||||
* Andrei Alexandrescu
|
||||
* $(WEB erdani.org, Andrei Alexandrescu)
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
|
@ -38,6 +38,8 @@
|
|||
|
||||
module std.contracts;
|
||||
private import std.conv;
|
||||
private import std.algorithm;
|
||||
private import std.iterator;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
|
@ -263,14 +265,13 @@ unittest
|
|||
* The call will duplicate the array appropriately.
|
||||
*
|
||||
* Checking for uniqueness during compilation is possible in certain
|
||||
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in the
|
||||
* $(LINK2 http://archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf,ArchJava)
|
||||
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in
|
||||
* the $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava)
|
||||
* language), but complicates the language considerably. The downside
|
||||
* of $(D_PARAM assumeUnique)'s
|
||||
* convention-based usage is that at this time there is no formal
|
||||
* checking of the correctness of the assumption; on the upside, the
|
||||
* idiomatic use of $(D_PARAM assumeUnique) is simple and rare enough
|
||||
* to make it tolerable.
|
||||
* of $(D_PARAM assumeUnique)'s convention-based usage is that at this
|
||||
* time there is no formal checking of the correctness of the
|
||||
* assumption; on the upside, the idiomatic use of $(D_PARAM
|
||||
* assumeUnique) is simple and rare enough to be tolerable.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -287,3 +288,76 @@ unittest
|
|||
auto arr1 = assumeUnique(arr);
|
||||
assert(is(typeof(arr1) == invariant(int)[]) && arr == null);
|
||||
}
|
||||
|
||||
invariant(T[U]) assumeUnique(T, U)(ref T[U] array)
|
||||
{
|
||||
auto result = cast(invariant(T[U])) array;
|
||||
array = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[string] arr = ["a":1];
|
||||
auto arr1 = assumeUnique(arr);
|
||||
assert(is(typeof(arr1) == invariant(int[string])) && arr == null);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns $(D true) if $(D source)'s representation embeds a pointer
|
||||
that points to $(D target)'s representation or somewhere inside
|
||||
it. Note that evaluating $(D pointsTo(x, x)) checks whether $(D x) has
|
||||
internal pointers.
|
||||
*/
|
||||
bool pointsTo(S, T)(ref S source, ref T target)
|
||||
{
|
||||
static if (is(S P : U*, U))
|
||||
{
|
||||
const void * m = source, b = &target, e = b + target.sizeof;
|
||||
return b <= m && m < e;
|
||||
}
|
||||
else static if (is(S == struct))
|
||||
{
|
||||
foreach (i, subobj; source.tupleof)
|
||||
{
|
||||
if (pointsTo(subobj, target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else static if (is(S A : U[], U))
|
||||
{
|
||||
const void* p1 = source.ptr, p2 = p1 + source.length,
|
||||
b = &target, e = b + target.sizeof;
|
||||
return overlap(range(p1, p2), range(b, e)).length != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
struct S1 { int a; S1 * b; }
|
||||
S1 a1;
|
||||
S1 * p = &a1;
|
||||
assert(pointsTo(p, a1));
|
||||
|
||||
S1 a2;
|
||||
a2.b = &a1;
|
||||
assert(pointsTo(a2, a1));
|
||||
|
||||
struct S3 { int[10] a; }
|
||||
S3 a3;
|
||||
auto a4 = a3.a[2 .. 3];
|
||||
assert(pointsTo(a4, a3));
|
||||
|
||||
auto a5 = new double[4];
|
||||
auto a6 = a5[1 .. 2];
|
||||
assert(!pointsTo(a5, a6));
|
||||
|
||||
auto a7 = new double[3];
|
||||
auto a8 = new double[][1];
|
||||
a8[0] = a7;
|
||||
assert(!pointsTo(a8[0], a8[0]));
|
||||
}
|
||||
|
|
21
std/conv.d
21
std/conv.d
|
@ -1,4 +1,3 @@
|
|||
|
||||
// Written in the D programming language.
|
||||
|
||||
/*
|
||||
|
@ -26,9 +25,13 @@
|
|||
*/
|
||||
|
||||
/***********
|
||||
* A one-stop shop for converting values from one type to another.
|
||||
*
|
||||
*/
|
||||
A one-stop shop for converting values from one type to another.
|
||||
|
||||
Authors:
|
||||
|
||||
$(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
|
||||
Alexandrescu)
|
||||
*/
|
||||
|
||||
module std.conv;
|
||||
|
||||
|
@ -196,14 +199,9 @@ might fail the range check.
|
|||
Macros: WIKI=Phobos/StdConv
|
||||
*/
|
||||
|
||||
template to(Target)
|
||||
Target to(Target, Source)(Source value)
|
||||
{
|
||||
Target to(Source)(Source value)
|
||||
{
|
||||
// Need to forward because of problems when recursively invoking
|
||||
// a member with the same name as a template
|
||||
return toImpl!(Source, Target)(value);
|
||||
}
|
||||
return toImpl!(Source, Target)(value);
|
||||
}
|
||||
|
||||
private T toSomeString(S, T)(S s)
|
||||
|
@ -2059,4 +2057,3 @@ private bool feq(in creal r1, in creal r2)
|
|||
|
||||
return feq(r1a, r2b, 0.000001L);
|
||||
}
|
||||
|
||||
|
|
58
std/file.d
58
std/file.d
|
@ -1,9 +1,17 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdFile
|
||||
*/
|
||||
Utilities for manipulating files and scanning directories.
|
||||
|
||||
Authors:
|
||||
|
||||
$(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
|
||||
Alexandrescu)
|
||||
|
||||
Macros:
|
||||
|
||||
WIKI = Phobos/StdFile
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001-2004 by Digital Mars, www.digitalmars.com
|
||||
|
@ -1037,42 +1045,24 @@ void remove(in string name)
|
|||
|
||||
ulong getSize(in string name)
|
||||
{
|
||||
uint size;
|
||||
int fd;
|
||||
struct_stat statbuf;
|
||||
|
||||
auto namez = toStringz(name);
|
||||
//printf("file.getSize('%s')\n",namez);
|
||||
fd = std.c.linux.linux.open(namez, O_RDONLY);
|
||||
if (fd == -1)
|
||||
if (std.c.linux.linux.stat(toStringz(name), &statbuf))
|
||||
{
|
||||
//printf("\topen error, errno = %d\n",getErrno());
|
||||
goto err1;
|
||||
throw new FileException(name, getErrno());
|
||||
}
|
||||
|
||||
//printf("\tfile opened\n");
|
||||
if (std.c.linux.linux.fstat(fd, &statbuf))
|
||||
{
|
||||
//printf("\tfstat error, errno = %d\n",getErrno());
|
||||
goto err2;
|
||||
}
|
||||
size = statbuf.st_size;
|
||||
|
||||
if (std.c.linux.linux.close(fd) == -1)
|
||||
{
|
||||
//printf("\tclose error, errno = %d\n",getErrno());
|
||||
goto err;
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
err2:
|
||||
std.c.linux.linux.close(fd);
|
||||
err:
|
||||
err1:
|
||||
throw new FileException(name.idup, getErrno());
|
||||
return statbuf.st_size;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
scope(exit) system("rm -f /tmp/deleteme");
|
||||
// create a file of size 1
|
||||
assert(system("echo > /tmp/deleteme") == 0);
|
||||
assert(getSize("/tmp/deleteme") == 1);
|
||||
// create a file of size 3
|
||||
assert(system("echo ab > /tmp/deleteme") == 0);
|
||||
assert(getSize("/tmp/deleteme") == 3);
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* Get file attributes.
|
||||
|
|
32
std/format.d
32
std/format.d
|
@ -1960,33 +1960,39 @@ private void formatFloat(Writer, D)(ref Writer w, D obj, FormatInfo f)
|
|||
private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
|
||||
FormatInfo f)
|
||||
{
|
||||
D obj = *cast(D*) arg;
|
||||
static if (is(D == void[])) {
|
||||
char[] s = cast(char[]) obj;
|
||||
auto obj = *cast(D*) arg;
|
||||
static if (is(const(D) == const(void[]))) {
|
||||
auto s = cast(const char[]) obj;
|
||||
w.write(s);
|
||||
} else static if (is(D Original == typedef)) {
|
||||
formatGeneric!(Writer, Original)(w, arg, f);
|
||||
} else static if (is(D == float) || is(D == double) || is(D == real)) {
|
||||
} else static if (is(const D == const(float))
|
||||
|| is(const(D) == const(double))
|
||||
|| is(const(D) == const(real))) {
|
||||
formatFloat(w, obj, f);
|
||||
} else static if (is(D == ifloat)) {
|
||||
} else static if (is(const(D) == const ifloat)) {
|
||||
formatFloat(w, *cast(float*) &obj, f);
|
||||
} else static if (is(D == idouble)) {
|
||||
} else static if (is(const(D) == const idouble)) {
|
||||
formatFloat(w, *cast(double*) &obj, f);
|
||||
} else static if (is(D == ireal)) {
|
||||
} else static if (is(const(D) == const ireal)) {
|
||||
formatFloat(w, *cast(real*) &obj, f);
|
||||
} else static if (is(D == cfloat) || is(D == cdouble) || is(D == creal)) {
|
||||
} else static if (is(const(D) == const cfloat)
|
||||
|| is(const(D) == const cdouble)
|
||||
|| is(const(D) == const creal)) {
|
||||
formatFloat(w, obj.re, f);
|
||||
w.write("+");
|
||||
formatFloat(w, obj.im, f);
|
||||
w.write("i");
|
||||
} else static if (is(D : long) || is(D : ulong)) {
|
||||
static if (is(D == bool)) {
|
||||
} else static if (is(const(D) : const long) || is(const(D) : const ulong)) {
|
||||
static if (is(const(D) == const bool)) {
|
||||
if (f.spec == 's') {
|
||||
w.write(obj ? "true" : "false");
|
||||
} else {
|
||||
formatIntegral(w, cast(int) obj, f);
|
||||
}
|
||||
} else static if (is(D == char) || is(D == wchar) || is(D == dchar)) {
|
||||
} else static if (is(const(D) == const char)
|
||||
|| is(const(D) == const wchar)
|
||||
|| is(const(D) == const dchar)) {
|
||||
if (f.spec == 's') {
|
||||
w.putchar(obj);
|
||||
} else {
|
||||
|
@ -2023,11 +2029,11 @@ private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
|
|||
formatGeneric!(Writer, typeof(e))(w, &e, f);
|
||||
}
|
||||
w.putchar(']');
|
||||
} else static if (is(D : void*)) {
|
||||
} else static if (is(const(D) : const void*)) {
|
||||
f.spec = 'X';
|
||||
ulong fake = cast(ulong) obj;
|
||||
formatGeneric!(Writer, ulong)(w, &fake, f);
|
||||
} else static if (is(D : Object)) {
|
||||
} else static if (is(const(D) : const Object)) {
|
||||
if (obj is null) w.write("null");
|
||||
else w.write(obj.toString);
|
||||
} else static if (isAssociativeArray!(D)) {
|
||||
|
|
224
std/functional.d
224
std/functional.d
|
@ -1,17 +1,15 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
This module is a port of a growing fragment of the $(D_PARAM
|
||||
functional) header in Alexander Stepanov's
|
||||
$(LINK2 http://sgi.com/tech/stl, Standard Template Library).
|
||||
Functions that manipulate other functions.
|
||||
|
||||
Macros:
|
||||
Macros:
|
||||
|
||||
WIKI = Phobos/StdFunctional
|
||||
WIKI = Phobos/StdFunctional
|
||||
|
||||
Author:
|
||||
Author:
|
||||
|
||||
Andrei Alexandrescu
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -38,12 +36,214 @@ $(LINK2 http://sgi.com/tech/stl, Standard Template Library).
|
|||
|
||||
module std.functional;
|
||||
|
||||
/**
|
||||
Predicate that returns $(D_PARAM a < b).
|
||||
*/
|
||||
bool less(T)(T a, T b) { return a < b; }
|
||||
import std.string; // for making string functions visible in *naryFun
|
||||
import std.conv; // for making conversions visible in *naryFun
|
||||
import std.typetuple;
|
||||
import std.typecons;
|
||||
import std.stdio;
|
||||
import std.metastrings;
|
||||
|
||||
/**
|
||||
Transforms a string representing an expression into a unary
|
||||
function. The string must use symbol name $(D a) as the parameter.
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
alias unaryFun!("(a & 1) == 0") isEven;
|
||||
assert(isEven(2) && !isEven(1));
|
||||
----
|
||||
*/
|
||||
|
||||
template unaryFun(string comp, bool byRef = false) {
|
||||
static if (byRef)
|
||||
{
|
||||
void unaryFun(ElementType)(ref ElementType a)
|
||||
{
|
||||
mixin(comp ~ ";");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// @@@BUG1816@@@: typeof(mixin(comp)) should work
|
||||
typeof({ ElementType a; return mixin(comp);}())
|
||||
unaryFun(ElementType)(ElementType a)
|
||||
{
|
||||
return mixin(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Transforms a string representing an expression into a Boolean binary
|
||||
predicate. The string must use symbol names $(D a) and $(D b) as the
|
||||
compared elements.
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
alias binaryFun!("a < b") less;
|
||||
assert(less(1, 2) && !less(2, 1));
|
||||
alias binaryFun!("a > b") greater;
|
||||
assert(!greater("1", "2") && greater("2", "1"));
|
||||
----
|
||||
*/
|
||||
|
||||
template binaryFun(string comp) {
|
||||
// @@@BUG1816@@@: typeof(mixin(comp)) should work
|
||||
typeof({ ElementType1 a; ElementType2 b; return mixin(comp);}())
|
||||
binaryFun(ElementType1, ElementType2)(ElementType1 a, ElementType2 b)
|
||||
{
|
||||
return mixin(comp);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
alias binaryFun!(q{a < b}) less;
|
||||
assert(less(1, 2) && !less(2, 1));
|
||||
assert(less("1", "2") && !less("2", "1"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Predicate that returns $(D_PARAM a < b).
|
||||
*/
|
||||
//bool less(T)(T a, T b) { return a < b; }
|
||||
//alias binaryFun!(q{a < b}) less;
|
||||
|
||||
/*
|
||||
Predicate that returns $(D_PARAM a > b).
|
||||
*/
|
||||
bool greater(T)(T a, T b) { return a > b; }
|
||||
//alias binaryFun!(q{a > b}) greater;
|
||||
|
||||
/*
|
||||
Predicate that returns $(D_PARAM a == b).
|
||||
*/
|
||||
//alias binaryFun!(q{a == b}) equalTo;
|
||||
|
||||
/*
|
||||
Binary predicate that reverses the order of arguments, e.g., given
|
||||
$(D pred(a, b)), returns $(D pred(b, a)).
|
||||
*/
|
||||
template binaryRevertArgs(alias pred)
|
||||
{
|
||||
typeof({ ElementType1 a; ElementType2 b; return pred(b, a);}())
|
||||
binaryRevertArgs(ElementType1, ElementType2)(ElementType1 a, ElementType2 b)
|
||||
{
|
||||
return pred(b, a);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
alias binaryRevertArgs!(binaryFun!("a < b")) gt;
|
||||
assert(gt(2, 1) && !gt(1, 1));
|
||||
int x = 42;
|
||||
bool xyz(int a, int b) { return a * x < b / x; }
|
||||
auto foo = &xyz;
|
||||
foo(4, 5);
|
||||
alias binaryRevertArgs!(foo) zyx;
|
||||
assert(zyx(5, 4) == foo(4, 5));
|
||||
}
|
||||
|
||||
template not(alias pred)
|
||||
{
|
||||
bool not(T...)(T args) { return !pred(args); }
|
||||
}
|
||||
|
||||
/*private*/ template Adjoin(F...)
|
||||
{
|
||||
template For(V...)
|
||||
{
|
||||
static if (F.length == 0)
|
||||
{
|
||||
alias TypeTuple!() Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias F[0] headFun;
|
||||
alias typeof({ V values; return headFun(values); }()) Head;
|
||||
alias TypeTuple!(Head, Adjoin!(F[1 .. $]).For!(V).Result) Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Takes multiple functions and adjoins them together. The result is a
|
||||
$(XREF typecons, Tuple) with one element per passed-in function. Upon
|
||||
invocation, the returned tuple is the adjoined results of all
|
||||
functions.
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
static bool f1(int a) { return a != 0; }
|
||||
static int f2(int a) { return a / 2; }
|
||||
auto x = adjoin!(f1, f2)(5);
|
||||
assert(is(typeof(x) == Tuple!(bool, int)));
|
||||
assert(x._0 == true && x._1 == 2);
|
||||
----
|
||||
*/
|
||||
template adjoin(F...)
|
||||
{
|
||||
Tuple!(Adjoin!(F).For!(V).Result) adjoin(V...)(V a)
|
||||
{
|
||||
typeof(return) result;
|
||||
foreach (i, r; F)
|
||||
{
|
||||
// @@@BUG@@@
|
||||
mixin("result.field!("~ToString!(i)~") = F[i](a);");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
static bool F1(int a) { return a != 0; }
|
||||
static int F2(int a) { return a / 2; }
|
||||
auto x = adjoin!(F1, F2)(5);
|
||||
alias Adjoin!(F1, F2).For!(int).Result R;
|
||||
assert(is(typeof(x) == Tuple!(bool, int)));
|
||||
assert(x._0 == true && x._1 == 2);
|
||||
}
|
||||
|
||||
// /*private*/ template NaryFun(string fun, string letter, V...)
|
||||
// {
|
||||
// static if (V.length == 0)
|
||||
// {
|
||||
// enum args = "";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// enum args = V[0].stringof~" "~letter~"; "
|
||||
// ~NaryFun!(fun, [letter[0] + 1], V[1..$]).args;
|
||||
// enum code = args ~ "return "~fun~";";
|
||||
// }
|
||||
// alias void Result;
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// writeln(NaryFun!("a * b * 2", "a", int, double).code);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// naryFun
|
||||
// */
|
||||
// template naryFun(string fun)
|
||||
// {
|
||||
// //NaryFun!(fun, "a", V).Result
|
||||
// int naryFun(V...)(V values)
|
||||
// {
|
||||
// enum string code = NaryFun!(fun, "a", V).code;
|
||||
// mixin(code);
|
||||
// }
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// alias naryFun!("a + b") test;
|
||||
// test(1, 2);
|
||||
// }
|
||||
|
|
80
std/getopt.d
80
std/getopt.d
|
@ -11,7 +11,11 @@
|
|||
* as was the case with the more traditional single-letter approach,
|
||||
* is provided but not enabled by default.
|
||||
*
|
||||
* Credits:
|
||||
Author:
|
||||
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
* This module and its documentation are inspired by Perl's
|
||||
* $(LINK2 http://perldoc.perl.org/Getopt/Long.html,Getopt::Long) module. The
|
||||
|
@ -55,13 +59,13 @@ import std.stdio; // for testing only
|
|||
---------
|
||||
import std.getopt;
|
||||
|
||||
string data = "file.dat";
|
||||
string data = "file.dat";
|
||||
int length = 24;
|
||||
bool verbose;
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
bool result = getopt(
|
||||
getopt(
|
||||
args,
|
||||
"length", &length, // numeric
|
||||
"file", &data, // string
|
||||
|
@ -77,16 +81,15 @@ void main(string[] args)
|
|||
right (the "bound" pointer). The option string in the call to
|
||||
$(D_PARAM getopt) should not start with a dash.
|
||||
|
||||
In all cases, the command-line options that were parsed and
|
||||
used by $(D_PARAM getopt) are removed from $(D_PARAM args). Whatever
|
||||
in the arguments did not look like an option is left in $(D_PARAM
|
||||
args) for further processing by the program. Values that were
|
||||
unaffected by the options are not touched, so a common idiom is to
|
||||
initialize options to their defaults and then invoke $(D_PARAM
|
||||
getopt). If a command-line argument is recognized as an option with a
|
||||
parameter and the parameter cannot be parsed properly (e.g. a number
|
||||
is expected but not present), a $(D_PARAM ConvError) exception is
|
||||
thrown.
|
||||
In all cases, the command-line options that were parsed and used by
|
||||
$(D_PARAM getopt) are removed from $(D_PARAM args). Whatever in the
|
||||
arguments did not look like an option is left in $(D_PARAM args) for
|
||||
further processing by the program. Values that were unaffected by the
|
||||
options are not touched, so a common idiom is to initialize options
|
||||
to their defaults and then invoke $(D_PARAM getopt). If a
|
||||
command-line argument is recognized as an option with a parameter and
|
||||
the parameter cannot be parsed properly (e.g. a number is expected
|
||||
but not present), a $(D_PARAM ConvError) exception is thrown.
|
||||
|
||||
Depending on the type of the pointer being bound, $(D_PARAM getopt)
|
||||
recognizes the following kinds of options:
|
||||
|
@ -96,7 +99,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
bool verbose, debugging;
|
||||
bool result = getopt(args, "verbose", &verbose, "debug", &debugging);
|
||||
getopt(args, "verbose", &verbose, "debug", &debugging);
|
||||
---------
|
||||
|
||||
$(LI $(I Numeric options.) If an option is bound to a numeric type, a
|
||||
|
@ -105,7 +108,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
uint timeout;
|
||||
bool result = getopt(args, "timeout", &timeout);
|
||||
getopt(args, "timeout", &timeout);
|
||||
---------
|
||||
|
||||
Invoking the program with "--timeout=5" or "--timeout 5" will set
|
||||
|
@ -117,7 +120,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
uint paranoid;
|
||||
bool result = getopt(args, "paranoid+", ¶noid);
|
||||
getopt(args, "paranoid+", ¶noid);
|
||||
---------
|
||||
|
||||
Invoking the program with "--paranoid --paranoid --paranoid" will set
|
||||
|
@ -133,7 +136,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
string outputFile;
|
||||
bool result = getopt(args, "output", &outputFile);
|
||||
getopt(args, "output", &outputFile);
|
||||
---------
|
||||
|
||||
Invoking the program with "--output=myfile.txt" or "--output
|
||||
|
@ -146,7 +149,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
string[] outputFiles;
|
||||
bool result = getopt(args, "output", &outputFiles);
|
||||
getopt(args, "output", &outputFiles);
|
||||
---------
|
||||
|
||||
Invoking the program with "--output=myfile.txt --output=yourfile.txt"
|
||||
|
@ -159,7 +162,7 @@ void main(string[] args)
|
|||
|
||||
---------
|
||||
double[string] tuningParms;
|
||||
bool result = getopt(args, "tune", &tuningParms);
|
||||
getopt(args, "tune", &tuningParms);
|
||||
---------
|
||||
|
||||
Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6"
|
||||
|
@ -191,7 +194,7 @@ void main(string[] args)
|
|||
verbosityLevel = 2;
|
||||
}
|
||||
}
|
||||
bool result = getopt(args, "verbose", &myHandler, "quiet", &myHandler);
|
||||
getopt(args, "verbose", &myHandler, "quiet", &myHandler);
|
||||
}
|
||||
---------
|
||||
|
||||
|
@ -218,7 +221,7 @@ void main(string[] args)
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
bool result = getopt(args, "verbosity", &myHandler);
|
||||
getopt(args, "verbosity", &myHandler);
|
||||
}
|
||||
---------
|
||||
))))
|
||||
|
@ -237,7 +240,9 @@ getopt(args, "verbose|loquacious|garrulous", &verbose);
|
|||
|
||||
$(B Case)
|
||||
|
||||
By default options are case-insensitive. You can change that behavior by passing $(D_PARAM getopt) the $(D_PARAM caseSensitive) directive like this:
|
||||
By default options are case-insensitive. You can change that behavior
|
||||
by passing $(D_PARAM getopt) the $(D_PARAM caseSensitive) directive
|
||||
like this:
|
||||
|
||||
---------
|
||||
bool foo, bar;
|
||||
|
@ -297,7 +302,7 @@ $(B Options Terminator)
|
|||
A lonesome double-dash terminates $(D_PARAM getopt) gathering. It is used to separate program options from other parameters (e.g. options to be passed to another program). Invoking the example above with "--foo -- --bar" parses foo but leaves "--bar" in $(D_PARAM args). The double-dash itself is removed from the argument array.
|
||||
*/
|
||||
|
||||
bool getopt(T...)(ref string[] args, T opts) {
|
||||
void getopt(T...)(ref string[] args, T opts) {
|
||||
configuration cfg;
|
||||
return getoptImpl(args, cfg, opts);
|
||||
}
|
||||
|
@ -323,7 +328,7 @@ enum config {
|
|||
noPassThrough,
|
||||
};
|
||||
|
||||
private bool getoptImpl(T...)(ref string[] args,
|
||||
private void getoptImpl(T...)(ref string[] args,
|
||||
ref configuration cfg, T opts)
|
||||
{
|
||||
static if (opts.length) {
|
||||
|
@ -337,6 +342,7 @@ private bool getoptImpl(T...)(ref string[] args,
|
|||
case config.noBundling: cfg.bundling = false; break;
|
||||
case config.passThrough: cfg.passThrough = true; break;
|
||||
case config.noPassThrough: cfg.passThrough = false; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
return getoptImpl(args, cfg, opts[1 .. $]);
|
||||
}
|
||||
|
@ -414,12 +420,10 @@ private bool getoptImpl(T...)(ref string[] args,
|
|||
if (a == "--") break; // end of options
|
||||
if (!cfg.passThrough)
|
||||
{
|
||||
writeln(stderr, "Unrecognized option ", a);
|
||||
return false;
|
||||
throw new Exception("Unrecognized option "~a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const
|
||||
|
@ -465,19 +469,19 @@ unittest
|
|||
uint paranoid = 2;
|
||||
string[] args = (["program.name",
|
||||
"--paranoid", "--paranoid", "--paranoid"]).dup;
|
||||
assert(getopt(args, "paranoid+", ¶noid));
|
||||
getopt(args, "paranoid+", ¶noid);
|
||||
assert(paranoid == 5, to!(string)(paranoid));
|
||||
|
||||
string data = "file.dat";
|
||||
string data = "file.dat";
|
||||
int length = 24;
|
||||
bool verbose = true;
|
||||
args = (["program.name", "--length=5",
|
||||
"--file", "dat.file", "--verbose"]).dup;
|
||||
assert(getopt(
|
||||
getopt(
|
||||
args,
|
||||
"length", &length,
|
||||
"file", &data,
|
||||
"verbose", &verbose));
|
||||
"verbose", &verbose);
|
||||
assert(args.length == 1);
|
||||
assert(data == "dat.file");
|
||||
assert(length == 5);
|
||||
|
@ -487,14 +491,14 @@ unittest
|
|||
string[] outputFiles;
|
||||
args = (["program.name", "--output=myfile.txt",
|
||||
"--output", "yourfile.txt"]).dup;
|
||||
assert(getopt(args, "output", &outputFiles));
|
||||
getopt(args, "output", &outputFiles);
|
||||
assert(outputFiles.length == 2
|
||||
&& outputFiles[0] == "myfile.txt" && outputFiles[0] == "myfile.txt");
|
||||
|
||||
args = (["program.name", "--tune=alpha=0.5",
|
||||
"--tune", "beta=0.6"]).dup;
|
||||
double[string] tuningParms;
|
||||
assert(getopt(args, "tune", &tuningParms));
|
||||
getopt(args, "tune", &tuningParms);
|
||||
assert(args.length == 1);
|
||||
assert(tuningParms.length == 2);
|
||||
assert(tuningParms["alpha"] == 0.5);
|
||||
|
@ -514,10 +518,10 @@ unittest
|
|||
}
|
||||
}
|
||||
args = (["program.name", "--quiet"]).dup;
|
||||
assert(getopt(args, "verbose", &myHandler, "quiet", &myHandler));
|
||||
getopt(args, "verbose", &myHandler, "quiet", &myHandler);
|
||||
assert(verbosityLevel == 0);
|
||||
args = (["program.name", "--verbose"]).dup;
|
||||
assert(getopt(args, "verbose", &myHandler, "quiet", &myHandler));
|
||||
getopt(args, "verbose", &myHandler, "quiet", &myHandler);
|
||||
assert(verbosityLevel == 2);
|
||||
|
||||
verbosityLevel = 1;
|
||||
|
@ -527,15 +531,15 @@ unittest
|
|||
verbosityLevel = 2;
|
||||
}
|
||||
args = (["program.name", "--verbose", "2"]).dup;
|
||||
assert(getopt(args, "verbose", &myHandler2));
|
||||
getopt(args, "verbose", &myHandler2);
|
||||
assert(verbosityLevel == 2);
|
||||
|
||||
bool foo, bar;
|
||||
args = (["program.name", "--foo", "--bAr"]).dup;
|
||||
assert(getopt(args,
|
||||
getopt(args,
|
||||
std.getopt.config.caseSensitive,
|
||||
std.getopt.config.passThrough,
|
||||
"foo", &foo,
|
||||
"bar", &bar));
|
||||
"bar", &bar);
|
||||
assert(args[1] == "--bAr");
|
||||
}
|
||||
|
|
|
@ -1946,11 +1946,7 @@ unittest
|
|||
bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 0)
|
||||
{
|
||||
static if (isArray!(T)) {
|
||||
<<<<<<< .mine
|
||||
invariant n = lhs.length;
|
||||
=======
|
||||
auto n = lhs.length;
|
||||
>>>>>>> .r582
|
||||
static if (isArray!(U)) {
|
||||
// Two arrays
|
||||
assert(n == rhs.length);
|
||||
|
|
|
@ -11,7 +11,7 @@ WIKI = Phobos/StdNumeric
|
|||
|
||||
Author:
|
||||
|
||||
Andrei Alexandrescu
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -52,7 +52,7 @@ Example:
|
|||
float f(float x) {
|
||||
return cos(x) - x*x*x;
|
||||
}
|
||||
final x = secantMethod(&f, 0f, 1f);
|
||||
auto x = secantMethod(&f, 0f, 1f);
|
||||
assert(approxEqual(x, 0.865474));
|
||||
----
|
||||
*/
|
||||
|
@ -79,7 +79,7 @@ unittest
|
|||
float f(float x) {
|
||||
return cos(x) - x*x*x;
|
||||
}
|
||||
auto x = secantMethod!(f)(0f, 1f);
|
||||
invariant x = secantMethod!(f)(0f, 1f);
|
||||
assert(approxEqual(x, 0.865474));
|
||||
}
|
||||
|
||||
|
|
20
std/path.d
20
std/path.d
|
@ -1,20 +1,24 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* This module is used to parse file names. All the operations work
|
||||
* only on strings; they don't perform any input/output
|
||||
* operations. This means that if a path contains a directory name
|
||||
* with a dot, functions like $(D getExt()) will work with it just as
|
||||
* if it was a file. To differentiate these cases, use the std.file
|
||||
* module first (i.e. $(D std.file.isDir())).
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* $(WEB digitalmars.com, Walter Bright), Grzegorz Adam Hankiewicz,
|
||||
Thomas Kühne, $(WEB erdani.org, Andrei Alexandrescu)
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdPath
|
||||
* Copyright:
|
||||
* Placed into public domain.
|
||||
* www.digitalmars.com
|
||||
*
|
||||
* Grzegorz Adam Hankiewicz added some documentation.
|
||||
*
|
||||
* This module is used to parse file names. All the operations
|
||||
* work only on strings; they don't perform any input/output
|
||||
* operations. This means that if a path contains a directory name
|
||||
* with a dot, functions like getExt() will work with it just as
|
||||
* if it was a file. To differentiate these cases,
|
||||
* use the std.file module first (i.e. std.file.isDir()).
|
||||
*/
|
||||
|
||||
module std.path;
|
||||
|
|
45
std/random.d
45
std/random.d
|
@ -37,7 +37,7 @@ integers and real numbers have been implemented.
|
|||
|
||||
Author:
|
||||
|
||||
Andrei Alexandrescu
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
|
||||
Credits:
|
||||
|
||||
|
@ -181,7 +181,7 @@ struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m)
|
|||
UIntType next()
|
||||
{
|
||||
static if (m)
|
||||
_x = (cast(ulong) a * _x + c) % m;
|
||||
_x = cast(UIntType) ((cast(ulong) a * _x + c) % m);
|
||||
else
|
||||
_x = a * _x + c;
|
||||
return _x;
|
||||
|
@ -334,6 +334,7 @@ struct MersenneTwisterEngine(
|
|||
}
|
||||
for (mti = 1; mti < n; ++mti) {
|
||||
mt[mti] =
|
||||
cast(UIntType)
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> (w - 2))) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
|
@ -367,15 +368,18 @@ struct MersenneTwisterEngine(
|
|||
for (; kk < n - m; ++kk)
|
||||
{
|
||||
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask);
|
||||
mt[kk] = mt[kk + m] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
mt[kk] = cast(UIntType) (mt[kk + m] ^ (y >> 1)
|
||||
^ mag01[cast(UIntType) y & 0x1U]);
|
||||
}
|
||||
for (; kk < n - 1; ++kk)
|
||||
{
|
||||
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask);
|
||||
mt[kk] = mt[kk + (m -n)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
mt[kk] = cast(UIntType) (mt[kk + (m -n)] ^ (y >> 1)
|
||||
^ mag01[cast(UIntType) y & 0x1U]);
|
||||
}
|
||||
y = (mt[n -1] & upperMask)|(mt[0] & lowerMask);
|
||||
mt[n - 1] = mt[m - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
mt[n - 1] = cast(UIntType) (mt[m - 1] ^ (y >> 1)
|
||||
^ mag01[cast(UIntType) y & 0x1U]);
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
@ -388,7 +392,7 @@ struct MersenneTwisterEngine(
|
|||
y ^= (y << temperingT) & temperingC;
|
||||
y ^= (y >> temperingL);
|
||||
|
||||
return y;
|
||||
return cast(UIntType) y;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -442,7 +446,7 @@ unittest
|
|||
for the minutiae of the method being used.
|
||||
*/
|
||||
|
||||
typedef Mt19937 Random;
|
||||
alias Mt19937 Random;
|
||||
|
||||
/**
|
||||
A "good" seed for initializing random number engines. Initializing
|
||||
|
@ -458,9 +462,9 @@ auto n = rnd.next;
|
|||
----
|
||||
*/
|
||||
|
||||
ulong unpredictableSeed()
|
||||
uint unpredictableSeed()
|
||||
{
|
||||
return cast(ulong) (getpid ^ getUTCtime);
|
||||
return cast(uint) (getpid ^ getUTCtime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -619,28 +623,27 @@ unittest
|
|||
----
|
||||
Random gen(unpredictableSeed);
|
||||
// Generate an integer in [0, 1024]
|
||||
auto a = uniform!(int)(gen, 0, 1024);
|
||||
auto a = uniform(gen, 0, 1024);
|
||||
// Generate a float in [0, 1$(RPAREN)
|
||||
auto a = uniform!(float)(gen, 0.0f, 1.0f);
|
||||
auto a = uniform(gen, 0.0f, 1.0f);
|
||||
----
|
||||
*/
|
||||
|
||||
template uniform(T, char leftLim = '[', char rightLim = ')')
|
||||
T1 uniform(T1, char leftLim = '[', char rightLim = ')',
|
||||
UniformRandomNumberGenerator, T2)
|
||||
(ref UniformRandomNumberGenerator gen, T1 a, T2 b)
|
||||
{
|
||||
T uniform(UniformRandomNumberGenerator)
|
||||
(ref UniformRandomNumberGenerator gen, T a, T b)
|
||||
{
|
||||
auto dist = UniformDistribution!(T, leftLim, rightLim)(a, b);
|
||||
return dist.next(gen);
|
||||
}
|
||||
alias typeof(return) Result;
|
||||
auto dist = UniformDistribution!(Result, leftLim, rightLim)(a, b);
|
||||
return dist.next(gen);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
auto gen = Mt19937(unpredictableSeed);
|
||||
auto a = uniform!(int)(gen, 0, 1024);
|
||||
auto a = uniform(gen, 0, 1024);
|
||||
assert(0 <= a && a <= 1024);
|
||||
auto b = uniform!(float)(gen, 0.0f, 1.0f);
|
||||
auto b = uniform(gen, 0.0f, 1.0f);
|
||||
assert(0 <= b && b < 1, to!(string)(b));
|
||||
}
|
||||
|
||||
|
@ -654,7 +657,7 @@ void randomShuffle(T, SomeRandomGen)(T[] array, ref SomeRandomGen r)
|
|||
foreach (i; 0 .. array.length)
|
||||
{
|
||||
// generate a random number i .. n
|
||||
auto which = i + uniform!(size_t)(r, 0u, array.length - i);
|
||||
invariant which = i + uniform!(size_t)(r, 0u, array.length - i);
|
||||
swap(array[i], array[which]);
|
||||
}
|
||||
}
|
||||
|
|
12
std/regexp.d
12
std/regexp.d
|
@ -25,11 +25,13 @@
|
|||
*/
|
||||
|
||||
/**********************************************
|
||||
* $(LINK2 http://www.digitalmars.com/ctg/regular.html, Regular expressions)
|
||||
* are a powerful method of string pattern matching.
|
||||
* The regular expression
|
||||
* language used is the same as that commonly used, however, some of the very
|
||||
* advanced forms may behave slightly differently.
|
||||
* $(LINK2 http://www.digitalmars.com/ctg/regular.html, Regular
|
||||
* expressions) are a powerful method of string pattern matching. The
|
||||
* regular expression language used in this library is the same as
|
||||
* that commonly used, however, some of the very advanced forms may
|
||||
* behave slightly differently. The standard observed is the $(WEB
|
||||
* www.ecma-international.org/publications/standards/Ecma-262.htm,
|
||||
* ECMA standard) for regular expressions.
|
||||
*
|
||||
* std.regexp is designed to work only with valid UTF strings as input.
|
||||
* To validate untrusted input, use std.utf.validate().
|
||||
|
|
13
std/stdio.d
13
std/stdio.d
|
@ -10,6 +10,12 @@
|
|||
* Standard I/O functions that extend $(B std.c.stdio).
|
||||
* $(B std.c.stdio) is $(D_PARAM public)ally imported when importing
|
||||
* $(B std.stdio).
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
|
||||
Alexandrescu)
|
||||
*
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdStdio
|
||||
*/
|
||||
|
@ -241,6 +247,9 @@ void write(T...)(T args)
|
|||
static const first = 0;
|
||||
}
|
||||
writef(target, "", args[first .. $]);
|
||||
static if (args.length && is(typeof(args[$ - 1]) : dchar)) {
|
||||
if (args[$ - 1] == '\n') fflush(target);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -1231,7 +1240,7 @@ struct chunks
|
|||
// if (fileName.length && fclose(f))
|
||||
// StdioException("Could not close file `"~fileName~"'");
|
||||
// }
|
||||
const maxStackSize = 500 * 1024;
|
||||
const maxStackSize = 1024 * 16;
|
||||
ubyte[] buffer = void;
|
||||
if (size < maxStackSize)
|
||||
buffer = (cast(ubyte*) alloca(size))[0 .. size];
|
||||
|
@ -1247,7 +1256,7 @@ struct chunks
|
|||
{
|
||||
// error occured
|
||||
if (!feof(f)) throw new StdioException(ferror(f));
|
||||
if (!r) break; // done reading
|
||||
buffer.length = r;
|
||||
}
|
||||
if ((result = dg(buffer)) != 0) break;
|
||||
}
|
||||
|
|
22
std/string.d
22
std/string.d
|
@ -2,15 +2,17 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* String handling functions.
|
||||
* String handling functions. Objects of types $(D string), $(D
|
||||
* wstring), and $(D dstring) are value types and cannot be mutated
|
||||
* element-by-element. For using mutation during building strings, use
|
||||
* $(D char[]), $(D wchar[]), or $(D dchar[]). The $(D *string) types
|
||||
* are preferable because they don't exhibit undesired aliasing, thus
|
||||
* making code more robust.
|
||||
*
|
||||
* To copy or not to copy?
|
||||
* When a function takes a string as a parameter, and returns a string,
|
||||
* is that string the same as the input string, modified in place, or
|
||||
* is it a modified copy of the input string? The D array convention is
|
||||
* "copy-on-write". This means that if no modifications are done, the
|
||||
* original string (or slices of it) can be returned. If any modifications
|
||||
* are done, the returned string is a copy.
|
||||
* Authors:
|
||||
*
|
||||
* $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
|
||||
Alexandrescu)
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdString
|
||||
|
@ -1607,8 +1609,8 @@ bool startsWith(A1, A2)(A1 longer, A2 shorter)
|
|||
if (longer[i] != e) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -1697,8 +1699,8 @@ bool endsWith(A1, A2)(A1 longer, A2 shorter)
|
|||
if (shorter[i] != e) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
|
@ -821,6 +821,8 @@ class Thread
|
|||
static Thread[] getAll()
|
||||
{
|
||||
synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
|
||||
// @@@BUG1819@@@
|
||||
return null;
|
||||
}
|
||||
|
||||
void pause()
|
||||
|
|
425
std/traits.d
425
std/traits.d
|
@ -1,23 +1,20 @@
|
|||
|
||||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* Templates with which to extract information about
|
||||
* types at compile time.
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* $(WEB digitalmars.com, Walter Bright), Tomasz Stachowiak ($(D
|
||||
* isExpressionTuple)), $(WEB erdani.org, Andrei Alexandrescu)
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdTraits
|
||||
* Copyright:
|
||||
* Public Domain
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Walter Bright, Digital Mars, www.digitalmars.com
|
||||
* Tomasz Stachowiak (isExpressionTuple)
|
||||
* Andrei Alexandrescu, www.erdani.org
|
||||
*/
|
||||
|
||||
module std.traits;
|
||||
import std.typetuple;
|
||||
|
||||
|
@ -119,12 +116,348 @@ template ParameterTypeTuple(dg)
|
|||
|
||||
template FieldTypeTuple(S)
|
||||
{
|
||||
static if (is(S == struct) || is(S == class))
|
||||
static if (is(S == struct) || is(S == class) || is(S == union))
|
||||
alias typeof(S.tupleof) FieldTypeTuple;
|
||||
else
|
||||
static assert(0, "argument is not struct or class");
|
||||
alias S FieldTypeTuple;
|
||||
//static assert(0, "argument is not struct or class");
|
||||
}
|
||||
|
||||
// // FieldOffsetsTuple
|
||||
// private template FieldOffsetsTupleImpl(size_t n, T...)
|
||||
// {
|
||||
// static if (T.length == 0)
|
||||
// {
|
||||
// alias TypeTuple!() Result;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //private alias FieldTypeTuple!(T[0]) Types;
|
||||
// private enum size_t myOffset =
|
||||
// ((n + T[0].alignof - 1) / T[0].alignof) * T[0].alignof;
|
||||
// static if (is(T[0] == struct))
|
||||
// {
|
||||
// alias FieldTypeTuple!(T[0]) MyRep;
|
||||
// alias FieldOffsetsTupleImpl!(myOffset, MyRep, T[1 .. $]).Result
|
||||
// Result;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// private enum size_t mySize = T[0].sizeof;
|
||||
// alias TypeTuple!(myOffset) Head;
|
||||
// static if (is(T == union))
|
||||
// {
|
||||
// alias FieldOffsetsTupleImpl!(myOffset, T[1 .. $]).Result
|
||||
// Tail;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// alias FieldOffsetsTupleImpl!(myOffset + mySize,
|
||||
// T[1 .. $]).Result
|
||||
// Tail;
|
||||
// }
|
||||
// alias TypeTuple!(Head, Tail) Result;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// template FieldOffsetsTuple(T...)
|
||||
// {
|
||||
// alias FieldOffsetsTupleImpl!(0, T).Result FieldOffsetsTuple;
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// alias FieldOffsetsTuple!(int) T1;
|
||||
// assert(T1.length == 1 && T1[0] == 0);
|
||||
// //
|
||||
// struct S2 { char a; int b; char c; double d; char e, f; }
|
||||
// alias FieldOffsetsTuple!(S2) T2;
|
||||
// //pragma(msg, T2);
|
||||
// static assert(T2.length == 6
|
||||
// && T2[0] == 0 && T2[1] == 4 && T2[2] == 8 && T2[3] == 16
|
||||
// && T2[4] == 24&& T2[5] == 25);
|
||||
// //
|
||||
// class C { int a, b, c, d; }
|
||||
// struct S3 { char a; C b; char c; }
|
||||
// alias FieldOffsetsTuple!(S3) T3;
|
||||
// //pragma(msg, T2);
|
||||
// static assert(T3.length == 3
|
||||
// && T3[0] == 0 && T3[1] == 4 && T3[2] == 8);
|
||||
// //
|
||||
// struct S4 { char a; union { int b; char c; } int d; }
|
||||
// alias FieldOffsetsTuple!(S4) T4;
|
||||
// //pragma(msg, FieldTypeTuple!(S4));
|
||||
// static assert(T4.length == 4
|
||||
// && T4[0] == 0 && T4[1] == 4 && T4[2] == 8);
|
||||
// }
|
||||
|
||||
// /***
|
||||
// Get the offsets of the fields of a struct or class.
|
||||
// */
|
||||
|
||||
// template FieldOffsetsTuple(S)
|
||||
// {
|
||||
// static if (is(S == struct) || is(S == class))
|
||||
// alias typeof(S.tupleof) FieldTypeTuple;
|
||||
// else
|
||||
// static assert(0, "argument is not struct or class");
|
||||
// }
|
||||
|
||||
/***
|
||||
Get the primitive types of the fields of a struct or class, in
|
||||
topological order.
|
||||
|
||||
Example:
|
||||
----
|
||||
struct S1 { int a; float b; }
|
||||
struct S2 { char[] a; union { S1 b; S1 * c; } }
|
||||
alias RepresentationTypeTuple!(S2) R;
|
||||
assert(R.length == 4
|
||||
&& is(R[0] == char[]) && is(R[1] == int)
|
||||
&& is(R[2] == float) && is(R[3] == S1*));
|
||||
----
|
||||
*/
|
||||
|
||||
template RepresentationTypeTuple(T...)
|
||||
{
|
||||
static if (T.length == 0)
|
||||
{
|
||||
alias TypeTuple!() RepresentationTypeTuple;
|
||||
}
|
||||
else
|
||||
{
|
||||
static if (is(T[0] == struct) || is(T[0] == union))
|
||||
// @@@BUG@@@ this should work
|
||||
// alias .RepresentationTypes!(T[0].tupleof)
|
||||
// RepresentationTypes;
|
||||
alias .RepresentationTypeTuple!(FieldTypeTuple!(T[0]),
|
||||
T[1 .. $])
|
||||
RepresentationTypeTuple;
|
||||
else static if (is(T[0] U == typedef))
|
||||
{
|
||||
alias .RepresentationTypeTuple!(FieldTypeTuple!(U),
|
||||
T[1 .. $])
|
||||
RepresentationTypeTuple;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias TypeTuple!(T[0], RepresentationTypeTuple!(T[1 .. $]))
|
||||
RepresentationTypeTuple;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
alias RepresentationTypeTuple!(int) S1;
|
||||
static assert(is(S1 == TypeTuple!(int)));
|
||||
struct S2 { int a; }
|
||||
static assert(is(RepresentationTypeTuple!(S2) == TypeTuple!(int)));
|
||||
struct S3 { int a; char b; }
|
||||
static assert(is(RepresentationTypeTuple!(S3) == TypeTuple!(int, char)));
|
||||
struct S4 { S1 a; int b; S3 c; }
|
||||
static assert(is(RepresentationTypeTuple!(S4) ==
|
||||
TypeTuple!(int, int, int, char)));
|
||||
|
||||
struct S11 { int a; float b; }
|
||||
struct S21 { char[] a; union { S11 b; S11 * c; } }
|
||||
alias RepresentationTypeTuple!(S21) R;
|
||||
assert(R.length == 4
|
||||
&& is(R[0] == char[]) && is(R[1] == int)
|
||||
&& is(R[2] == float) && is(R[3] == S11*));
|
||||
}
|
||||
|
||||
/*
|
||||
RepresentationOffsets
|
||||
*/
|
||||
|
||||
// private template Repeat(size_t n, T...)
|
||||
// {
|
||||
// static if (n == 0) alias TypeTuple!() Repeat;
|
||||
// else alias TypeTuple!(T, Repeat!(n - 1, T)) Repeat;
|
||||
// }
|
||||
|
||||
// template RepresentationOffsetsImpl(size_t n, T...)
|
||||
// {
|
||||
// static if (T.length == 0)
|
||||
// {
|
||||
// alias TypeTuple!() Result;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// private enum size_t myOffset =
|
||||
// ((n + T[0].alignof - 1) / T[0].alignof) * T[0].alignof;
|
||||
// static if (!is(T[0] == union))
|
||||
// {
|
||||
// alias Repeat!(n, FieldTypeTuple!(T[0])).Result
|
||||
// Head;
|
||||
// }
|
||||
// static if (is(T[0] == struct))
|
||||
// {
|
||||
// alias .RepresentationOffsetsImpl!(n, FieldTypeTuple!(T[0])).Result
|
||||
// Head;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// alias TypeTuple!(myOffset) Head;
|
||||
// }
|
||||
// alias TypeTuple!(Head,
|
||||
// RepresentationOffsetsImpl!(
|
||||
// myOffset + T[0].sizeof, T[1 .. $]).Result)
|
||||
// Result;
|
||||
// }
|
||||
// }
|
||||
|
||||
// template RepresentationOffsets(T)
|
||||
// {
|
||||
// alias RepresentationOffsetsImpl!(0, T).Result
|
||||
// RepresentationOffsets;
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// struct S1 { char c; int i; }
|
||||
// alias RepresentationOffsets!(S1) Offsets;
|
||||
// static assert(Offsets[0] == 0);
|
||||
// //pragma(msg, Offsets[1]);
|
||||
// static assert(Offsets[1] == 4);
|
||||
// }
|
||||
|
||||
// hasRawAliasing
|
||||
|
||||
private template HasRawPointerImpl(T...)
|
||||
{
|
||||
static if (T.length == 0)
|
||||
{
|
||||
enum result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
static if (is(T[0] foo : U*, U))
|
||||
enum hasRawAliasing = !is(U == invariant);
|
||||
else static if (is(T[0] foo : U[], U))
|
||||
enum hasRawAliasing = !is(U == invariant);
|
||||
else
|
||||
enum hasRawAliasing = false;
|
||||
enum result = hasRawAliasing || HasRawPointerImpl!(T[1 .. $]).result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Statically evaluates to $(D true) if and only if $(D T)'s
|
||||
representation contains at least one field of pointer or array type.
|
||||
Members of class types are not considered raw pointers. Pointers to
|
||||
invariant objects are not considered raw aliasing.
|
||||
|
||||
Example:
|
||||
---
|
||||
// simple types
|
||||
static assert(!hasRawAliasing!(int));
|
||||
static assert(hasRawAliasing!(char*));
|
||||
// references aren't raw pointers
|
||||
static assert(!hasRawAliasing!(Object));
|
||||
// built-in arrays do contain raw pointers
|
||||
static assert(hasRawAliasing!(int[]));
|
||||
// aggregate of simple types
|
||||
struct S1 { int a; double b; }
|
||||
static assert(!hasRawAliasing!(S1));
|
||||
// indirect aggregation
|
||||
struct S2 { S1 a; double b; }
|
||||
static assert(!hasRawAliasing!(S2));
|
||||
// struct with a pointer member
|
||||
struct S3 { int a; double * b; }
|
||||
static assert(hasRawAliasing!(S3));
|
||||
// struct with an indirect pointer member
|
||||
struct S4 { S3 a; double b; }
|
||||
static assert(hasRawAliasing!(S4));
|
||||
----
|
||||
*/
|
||||
private template hasRawAliasing(T...)
|
||||
{
|
||||
enum hasRawAliasing
|
||||
= HasRawPointerImpl!(RepresentationTypeTuple!(T)).result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
// simple types
|
||||
static assert(!hasRawAliasing!(int));
|
||||
static assert(hasRawAliasing!(char*));
|
||||
// references aren't raw pointers
|
||||
static assert(!hasRawAliasing!(Object));
|
||||
static assert(!hasRawAliasing!(int));
|
||||
struct S1 { int z; }
|
||||
static assert(!hasRawAliasing!(S1));
|
||||
struct S2 { int* z; }
|
||||
static assert(hasRawAliasing!(S2));
|
||||
struct S3 { int a; int* z; int c; }
|
||||
static assert(hasRawAliasing!(S3));
|
||||
struct S4 { int a; int z; int c; }
|
||||
static assert(!hasRawAliasing!(S4));
|
||||
struct S5 { int a; Object z; int c; }
|
||||
static assert(!hasRawAliasing!(S5));
|
||||
union S6 { int a; int b; }
|
||||
static assert(!hasRawAliasing!(S6));
|
||||
union S7 { int a; int * b; }
|
||||
static assert(hasRawAliasing!(S7));
|
||||
typedef int* S8;
|
||||
static assert(hasRawAliasing!(S8));
|
||||
enum S9 { a };
|
||||
static assert(!hasRawAliasing!(S9));
|
||||
// indirect members
|
||||
struct S10 { S7 a; int b; }
|
||||
static assert(hasRawAliasing!(S10));
|
||||
struct S11 { S6 a; int b; }
|
||||
static assert(!hasRawAliasing!(S11));
|
||||
}
|
||||
|
||||
/*
|
||||
Statically evaluates to $(D true) if and only if $(D T)'s
|
||||
representation includes at least one non-invariant object reference.
|
||||
*/
|
||||
|
||||
private template hasObjects(T...)
|
||||
{
|
||||
static if (T.length == 0)
|
||||
{
|
||||
enum hasObjects = false;
|
||||
}
|
||||
else static if (is(T[0] U == typedef))
|
||||
{
|
||||
enum hasObjects = hasObjects!(U, T[1 .. $]);
|
||||
}
|
||||
else static if (is(T[0] == struct))
|
||||
{
|
||||
enum hasObjects = hasObjects!(
|
||||
RepresentationTypeTuple!(T[0]), T[1 .. $]);
|
||||
}
|
||||
else
|
||||
{
|
||||
enum hasObjects = is(T[0] == class) || hasObjects!(T[1 .. $]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns $(D true) if and only if $(D T)'s representation includes at
|
||||
least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U)
|
||||
is not invariant;) $(LI an array $(D U[]) and $(D U) is not
|
||||
invariant;) $(LI a reference to a class type $(D C) and $(D C) is not
|
||||
invariant.))
|
||||
*/
|
||||
|
||||
template hasAliasing(T...)
|
||||
{
|
||||
enum hasAliasing = hasRawAliasing!(T) || hasObjects!(T);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
struct S1 { int a; Object b; }
|
||||
static assert(hasAliasing!(S1));
|
||||
struct S2 { string a; }
|
||||
static assert(!hasAliasing!(S2));
|
||||
}
|
||||
|
||||
/***
|
||||
* Get a $(D_PARAM TypeTuple) of the base class and base interfaces of
|
||||
|
@ -209,18 +542,68 @@ template BaseClassesTuple(T)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a $(D_PARAM TypeTuple) of $(I all) interfaces directly or
|
||||
* indirectly inherited by this class or interface. Interfaces do not
|
||||
* repeat if multiply implemented. $(D_PARAM InterfacesTuple!(Object))
|
||||
* yields the empty type tuple.
|
||||
*
|
||||
* Example:
|
||||
* ---
|
||||
* import std.traits, std.typetuple, std.stdio;
|
||||
* interface I1 { }
|
||||
* interface I2 { }
|
||||
* class A : I1, I2 { }
|
||||
* class B : A, I1 { }
|
||||
* class C : B { }
|
||||
*
|
||||
* void main()
|
||||
* {
|
||||
* alias InterfacesTuple!(C) TL;
|
||||
* writeln(typeid(TL)); // prints: (I1, I2)
|
||||
* }
|
||||
* ---
|
||||
*/
|
||||
|
||||
template InterfacesTuple(T)
|
||||
{
|
||||
static if (is(T == Object))
|
||||
{
|
||||
alias TypeTuple!() InterfacesTuple;
|
||||
}
|
||||
static if (is(BaseTypeTuple!(T)[0] == Object))
|
||||
{
|
||||
alias TypeTuple!(BaseTypeTuple!(T)[1 .. $]) InterfacesTuple;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias NoDuplicates!(
|
||||
TypeTuple!(BaseTypeTuple!(T)[1 .. $], // direct interfaces
|
||||
InterfacesTuple!(BaseTypeTuple!(T)[0])))
|
||||
InterfacesTuple;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
class B1 {}
|
||||
{
|
||||
// doc example
|
||||
class A : I1, I2 { }
|
||||
class B : A, I1 { }
|
||||
class C : B { }
|
||||
alias InterfacesTuple!(C) TL;
|
||||
assert(is(TL[0] == I1) && is(TL[1] == I2));
|
||||
}
|
||||
class B1 : I1, I2 {}
|
||||
class B2 : B1, I1 {}
|
||||
class B3 : B2, I2 {}
|
||||
alias BaseClassesTuple!(B3) TL;
|
||||
assert(TL.length == 3);
|
||||
assert(is (TL[0] == B2));
|
||||
assert(is (TL[1] == B1));
|
||||
assert(is (TL[2] == Object));
|
||||
alias InterfacesTuple!(B3) TL;
|
||||
//
|
||||
assert(TL.length == 2);
|
||||
assert(is (TL[0] == I2));
|
||||
assert(is (TL[1] == I1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,23 +634,25 @@ template TransitiveBaseTypeTuple(T)
|
|||
alias TypeTuple!() TransitiveBaseTypeTuple;
|
||||
else
|
||||
alias TypeTuple!(BaseClassesTuple!(T),
|
||||
BaseTypeTuple!(T)[1 .. $])
|
||||
InterfacesTuple!(T))
|
||||
TransitiveBaseTypeTuple;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
class B1 {}
|
||||
class B2 : B1 {}
|
||||
class B2 : B1, I1, I2 {}
|
||||
class B3 : B2, I1 {}
|
||||
alias TransitiveBaseTypeTuple!(B3) TL;
|
||||
assert(TL.length == 4);
|
||||
assert(TL.length == 5);
|
||||
assert(is (TL[0] == B2));
|
||||
assert(is (TL[1] == B1));
|
||||
assert(is (TL[2] == Object));
|
||||
assert(is (TL[3] == I1));
|
||||
|
||||
assert(is (TL[4] == I2));
|
||||
|
||||
assert(TransitiveBaseTypeTuple!(Object).length == 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue