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:
Andrei Alexandrescu 2008-02-19 07:00:56 +00:00
parent 0aea504e90
commit 29f3cc23f7
17 changed files with 3948 additions and 493 deletions

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,11 @@
/** /**
Bit-level manipulation facilities. Bit-level manipulation facilities.
Authors:
$(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
Alexandrescu)
Macros: Macros:
WIKI = StdBitarray WIKI = StdBitarray
*/ */
@ -12,28 +17,23 @@ module std.bitmanip;
//debug = bitarray; // uncomment to turn on debugging printf's //debug = bitarray; // uncomment to turn on debugging printf's
private import std.intrinsic; 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 static if (n < 10)
? "" ~ cast(char) (n + '0') enum myToString = cast(char) (n + '0') ~ suffix;
: myToString(n / 10) ~ myToString(n % 10); else
enum myToString = .myToString!(n / 10, "")
~ .myToString!(n % 10, "") ~ suffix;
} }
private string toStringSfx(ulong n) private template createAccessors(
{ string store, T, string name, size_t len, size_t offset)
return myToString(n) ~ (n > uint.max ? "UL" : "U");
}
private string createAccessors(
string store, T, string name, size_t len, size_t offset)()
{ {
static if (!name.length) static if (!name.length)
{ {
// No need to create any accessor // No need to create any accessor
return ""; enum result = "";
} }
else else
{ {
@ -47,52 +47,49 @@ private string createAccessors(
signBitCheck = 1uL << (len - 1), signBitCheck = 1uL << (len - 1),
extendSign = ~((cast(MasksType)1u << len) - 1); extendSign = ~((cast(MasksType)1u << len) - 1);
string result;
static if (is(T == bool)) static if (is(T == bool))
{ {
static assert(len == 1); static assert(len == 1);
enum result =
// getter // getter
result ~= "bool " ~ name ~ "(){ return " "bool " ~ name ~ "(){ return "
"("~store~" & "~toStringSfx(maskAllElse)~") != 0;}\n"; ~"("~store~" & "~myToString!(maskAllElse)~") != 0;}\n"
// setter // setter
result ~= "void " ~ name ~ "(bool v){" ~"void " ~ name ~ "(bool v){"
"if (v) "~store~" |= "~toStringSfx(maskAllElse)~";" ~"if (v) "~store~" |= "~myToString!(maskAllElse)~";"
"else "~store~" &= "~toStringSfx(maskMyself)~";}\n"; ~"else "~store~" &= "~myToString!(maskMyself)~";}\n";
} }
else else
{ {
// getter // getter
result ~= T.stringof ~ " " ~ name ~ "(){ auto result = " enum result = T.stringof ~ " " ~ name ~ "(){ auto result = "
"("~store~" & " "("~store~" & "
~ toStringSfx(maskAllElse) ~ ") >>" ~ myToString!(maskAllElse) ~ ") >>"
~ toStringSfx(offset) ~ ";"; ~ myToString!(offset) ~ ";"
static if (T.min < 0) ~ (T.min < 0
{ ? "if (result >= " ~ myToString!(signBitCheck)
result ~= "if (result >= " ~ toStringSfx(signBitCheck) ~ ") result |= " ~ myToString!(extendSign) ~ ";"
~ ") result |= " ~ toStringSfx(extendSign) ~ ";"; : "")
} ~ " return cast("~T.stringof~") result;}\n"
result ~= " return cast("~T.stringof~") result;}\n";
// setter // setter
result ~= "void " ~ name ~ "(" ~ T.stringof ~"void "~name~"("~T.stringof~" v){ "
~ " v){ "~store~" = ("~store~" & " ~store~" = cast(typeof("~store~"))"
~ toStringSfx(maskMyself) ~ ") | " " (("~store~" & "~myToString!(maskMyself)~")"
~ "((cast(typeof("~store~")) v << " ~ toStringSfx(offset) " | ((cast(typeof("~store~")) v << "~myToString!(offset)~")"
~ ") & " ~ toStringSfx(maskAllElse) " & "~myToString!(maskAllElse)~"));}\n";
~ ");}\n";
} }
return result;
} }
} }
private string createStoreName(Ts...)() private template createStoreName(Ts...)
{ {
static if (Ts.length == 0) static if (Ts.length < 2)
return ""; enum createStoreName = "";
else 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) static if (!Ts.length)
{ {
@ -106,12 +103,13 @@ private string createFields(string store, size_t offset, Ts...)()
alias ulong StoreType; alias ulong StoreType;
else else
static assert(false, myToString(offset)); static assert(false, myToString(offset));
return "private " ~ StoreType.stringof ~ " " ~ store ~ ";"; enum result = "private " ~ StoreType.stringof ~ " " ~ store ~ ";";
} }
else else
{ {
return createAccessors!(store, Ts[0], Ts[1], Ts[2], offset)() enum result
~ createFields!(store, offset + Ts[2], Ts[3 .. $])(); = 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...) 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 Allows manipulating the fraction, exponent, and sign parts of a
$(D_PARAM float) separately. The definition is: $(D_PARAM float) separately. The definition is:
@ -258,7 +254,6 @@ unittest
ubyte, "z", 5)); ubyte, "z", 5));
} }
} }
}
/** /**
* An array of bits. * An array of bits.
@ -305,7 +300,7 @@ struct BitArray
/********************************************** /**********************************************
* Support for [$(I index)] operation for BitArray. * Support for [$(I index)] operation for BitArray.
*/ */
bool opIndex(size_t i) bool opIndex(size_t i) const
in in
{ {
assert(i < len); assert(i < len);
@ -315,6 +310,19 @@ struct BitArray
return cast(bool)bt(ptr, i); 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 */ /** ditto */
bool opIndexAssign(bool b, size_t i) bool opIndexAssign(bool b, size_t i)
in in

View file

@ -29,7 +29,7 @@
* *
* Author: * Author:
* *
* Andrei Alexandrescu * $(WEB erdani.org, Andrei Alexandrescu)
* *
* Credits: * Credits:
* *
@ -38,6 +38,8 @@
module std.contracts; module std.contracts;
private import std.conv; private import std.conv;
private import std.algorithm;
private import std.iterator;
/* /*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
@ -263,14 +265,13 @@ unittest
* The call will duplicate the array appropriately. * The call will duplicate the array appropriately.
* *
* Checking for uniqueness during compilation is possible in certain * Checking for uniqueness during compilation is possible in certain
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in the * cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in
* $(LINK2 http://archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf,ArchJava) * the $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava)
* language), but complicates the language considerably. The downside * language), but complicates the language considerably. The downside
* of $(D_PARAM assumeUnique)'s * of $(D_PARAM assumeUnique)'s convention-based usage is that at this
* convention-based usage is that at this time there is no formal * time there is no formal checking of the correctness of the
* checking of the correctness of the assumption; on the upside, the * assumption; on the upside, the idiomatic use of $(D_PARAM
* idiomatic use of $(D_PARAM assumeUnique) is simple and rare enough * assumeUnique) is simple and rare enough to be tolerable.
* to make it tolerable.
* *
*/ */
@ -287,3 +288,76 @@ unittest
auto arr1 = assumeUnique(arr); auto arr1 = assumeUnique(arr);
assert(is(typeof(arr1) == invariant(int)[]) && arr == null); 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]));
}

View file

@ -1,4 +1,3 @@
// Written in the D programming language. // Written in the D programming language.
/* /*
@ -26,8 +25,12 @@
*/ */
/*********** /***********
* 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; module std.conv;
@ -196,15 +199,10 @@ might fail the range check.
Macros: WIKI=Phobos/StdConv 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) 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); return feq(r1a, r2b, 0.000001L);
} }

View file

@ -1,8 +1,16 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
* Macros: Utilities for manipulating files and scanning directories.
* WIKI = Phobos/StdFile
Authors:
$(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
Alexandrescu)
Macros:
WIKI = Phobos/StdFile
*/ */
/* /*
@ -1037,42 +1045,24 @@ void remove(in string name)
ulong getSize(in string name) ulong getSize(in string name)
{ {
uint size;
int fd;
struct_stat statbuf; struct_stat statbuf;
if (std.c.linux.linux.stat(toStringz(name), &statbuf))
auto namez = toStringz(name);
//printf("file.getSize('%s')\n",namez);
fd = std.c.linux.linux.open(namez, O_RDONLY);
if (fd == -1)
{ {
//printf("\topen error, errno = %d\n",getErrno()); throw new FileException(name, getErrno());
goto err1; }
return statbuf.st_size;
} }
//printf("\tfile opened\n"); unittest
if (std.c.linux.linux.fstat(fd, &statbuf))
{ {
//printf("\tfstat error, errno = %d\n",getErrno()); scope(exit) system("rm -f /tmp/deleteme");
goto err2; // 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);
} }
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());
}
/*************************************************** /***************************************************
* Get file attributes. * Get file attributes.

View file

@ -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, private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
FormatInfo f) FormatInfo f)
{ {
D obj = *cast(D*) arg; auto obj = *cast(D*) arg;
static if (is(D == void[])) { static if (is(const(D) == const(void[]))) {
char[] s = cast(char[]) obj; auto s = cast(const char[]) obj;
w.write(s); w.write(s);
} else static if (is(D Original == typedef)) { } else static if (is(D Original == typedef)) {
formatGeneric!(Writer, Original)(w, arg, f); 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); formatFloat(w, obj, f);
} else static if (is(D == ifloat)) { } else static if (is(const(D) == const ifloat)) {
formatFloat(w, *cast(float*) &obj, f); 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); 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); 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); formatFloat(w, obj.re, f);
w.write("+"); w.write("+");
formatFloat(w, obj.im, f); formatFloat(w, obj.im, f);
w.write("i"); w.write("i");
} else static if (is(D : long) || is(D : ulong)) { } else static if (is(const(D) : const long) || is(const(D) : const ulong)) {
static if (is(D == bool)) { static if (is(const(D) == const bool)) {
if (f.spec == 's') { if (f.spec == 's') {
w.write(obj ? "true" : "false"); w.write(obj ? "true" : "false");
} else { } else {
formatIntegral(w, cast(int) obj, f); 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') { if (f.spec == 's') {
w.putchar(obj); w.putchar(obj);
} else { } else {
@ -2023,11 +2029,11 @@ private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
formatGeneric!(Writer, typeof(e))(w, &e, f); formatGeneric!(Writer, typeof(e))(w, &e, f);
} }
w.putchar(']'); w.putchar(']');
} else static if (is(D : void*)) { } else static if (is(const(D) : const void*)) {
f.spec = 'X'; f.spec = 'X';
ulong fake = cast(ulong) obj; ulong fake = cast(ulong) obj;
formatGeneric!(Writer, ulong)(w, &fake, f); 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"); if (obj is null) w.write("null");
else w.write(obj.toString); else w.write(obj.toString);
} else static if (isAssociativeArray!(D)) { } else static if (isAssociativeArray!(D)) {

View file

@ -1,9 +1,7 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
This module is a port of a growing fragment of the $(D_PARAM Functions that manipulate other functions.
functional) header in Alexander Stepanov's
$(LINK2 http://sgi.com/tech/stl, Standard Template Library).
Macros: Macros:
@ -11,7 +9,7 @@ $(LINK2 http://sgi.com/tech/stl, Standard Template Library).
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; module std.functional;
/** import std.string; // for making string functions visible in *naryFun
Predicate that returns $(D_PARAM a < b). import std.conv; // for making conversions visible in *naryFun
*/ import std.typetuple;
bool less(T)(T a, T b) { return a < b; } 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). 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);
// }

View file

@ -11,6 +11,10 @@
* as was the case with the more traditional single-letter approach, * as was the case with the more traditional single-letter approach,
* is provided but not enabled by default. * is provided but not enabled by default.
* *
Author:
$(WEB erdani.org, Andrei Alexandrescu)
*
* Credits: * Credits:
* *
* This module and its documentation are inspired by Perl's * This module and its documentation are inspired by Perl's
@ -61,7 +65,7 @@ bool verbose;
void main(string[] args) void main(string[] args)
{ {
bool result = getopt( getopt(
args, args,
"length", &length, // numeric "length", &length, // numeric
"file", &data, // string "file", &data, // string
@ -77,16 +81,15 @@ void main(string[] args)
right (the "bound" pointer). The option string in the call to right (the "bound" pointer). The option string in the call to
$(D_PARAM getopt) should not start with a dash. $(D_PARAM getopt) should not start with a dash.
In all cases, the command-line options that were parsed and In all cases, the command-line options that were parsed and used by
used by $(D_PARAM getopt) are removed from $(D_PARAM args). Whatever $(D_PARAM getopt) are removed from $(D_PARAM args). Whatever in the
in the arguments did not look like an option is left in $(D_PARAM arguments did not look like an option is left in $(D_PARAM args) for
args) for further processing by the program. Values that were further processing by the program. Values that were unaffected by the
unaffected by the options are not touched, so a common idiom is to options are not touched, so a common idiom is to initialize options
initialize options to their defaults and then invoke $(D_PARAM to their defaults and then invoke $(D_PARAM getopt). If a
getopt). If a command-line argument is recognized as an option with a command-line argument is recognized as an option with a parameter and
parameter and the parameter cannot be parsed properly (e.g. a number the parameter cannot be parsed properly (e.g. a number is expected
is expected but not present), a $(D_PARAM ConvError) exception is but not present), a $(D_PARAM ConvError) exception is thrown.
thrown.
Depending on the type of the pointer being bound, $(D_PARAM getopt) Depending on the type of the pointer being bound, $(D_PARAM getopt)
recognizes the following kinds of options: recognizes the following kinds of options:
@ -96,7 +99,7 @@ void main(string[] args)
--------- ---------
bool verbose, debugging; 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 $(LI $(I Numeric options.) If an option is bound to a numeric type, a
@ -105,7 +108,7 @@ void main(string[] args)
--------- ---------
uint timeout; uint timeout;
bool result = getopt(args, "timeout", &timeout); getopt(args, "timeout", &timeout);
--------- ---------
Invoking the program with "--timeout=5" or "--timeout 5" will set Invoking the program with "--timeout=5" or "--timeout 5" will set
@ -117,7 +120,7 @@ void main(string[] args)
--------- ---------
uint paranoid; uint paranoid;
bool result = getopt(args, "paranoid+", &paranoid); getopt(args, "paranoid+", &paranoid);
--------- ---------
Invoking the program with "--paranoid --paranoid --paranoid" will set Invoking the program with "--paranoid --paranoid --paranoid" will set
@ -133,7 +136,7 @@ void main(string[] args)
--------- ---------
string outputFile; string outputFile;
bool result = getopt(args, "output", &outputFile); getopt(args, "output", &outputFile);
--------- ---------
Invoking the program with "--output=myfile.txt" or "--output Invoking the program with "--output=myfile.txt" or "--output
@ -146,7 +149,7 @@ void main(string[] args)
--------- ---------
string[] outputFiles; string[] outputFiles;
bool result = getopt(args, "output", &outputFiles); getopt(args, "output", &outputFiles);
--------- ---------
Invoking the program with "--output=myfile.txt --output=yourfile.txt" Invoking the program with "--output=myfile.txt --output=yourfile.txt"
@ -159,7 +162,7 @@ void main(string[] args)
--------- ---------
double[string] tuningParms; 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" Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6"
@ -191,7 +194,7 @@ void main(string[] args)
verbosityLevel = 2; 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); exit(1);
} }
} }
bool result = getopt(args, "verbosity", &myHandler); getopt(args, "verbosity", &myHandler);
} }
--------- ---------
)))) ))))
@ -237,7 +240,9 @@ getopt(args, "verbose|loquacious|garrulous", &verbose);
$(B Case) $(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; 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. 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; configuration cfg;
return getoptImpl(args, cfg, opts); return getoptImpl(args, cfg, opts);
} }
@ -323,7 +328,7 @@ enum config {
noPassThrough, noPassThrough,
}; };
private bool getoptImpl(T...)(ref string[] args, private void getoptImpl(T...)(ref string[] args,
ref configuration cfg, T opts) ref configuration cfg, T opts)
{ {
static if (opts.length) { static if (opts.length) {
@ -337,6 +342,7 @@ private bool getoptImpl(T...)(ref string[] args,
case config.noBundling: cfg.bundling = false; break; case config.noBundling: cfg.bundling = false; break;
case config.passThrough: cfg.passThrough = true; break; case config.passThrough: cfg.passThrough = true; break;
case config.noPassThrough: cfg.passThrough = false; break; case config.noPassThrough: cfg.passThrough = false; break;
default: assert(false); break;
} }
return getoptImpl(args, cfg, opts[1 .. $]); return getoptImpl(args, cfg, opts[1 .. $]);
} }
@ -414,12 +420,10 @@ private bool getoptImpl(T...)(ref string[] args,
if (a == "--") break; // end of options if (a == "--") break; // end of options
if (!cfg.passThrough) if (!cfg.passThrough)
{ {
writeln(stderr, "Unrecognized option ", a); throw new Exception("Unrecognized option "~a);
return false;
} }
} }
} }
return true;
} }
const const
@ -465,7 +469,7 @@ unittest
uint paranoid = 2; uint paranoid = 2;
string[] args = (["program.name", string[] args = (["program.name",
"--paranoid", "--paranoid", "--paranoid"]).dup; "--paranoid", "--paranoid", "--paranoid"]).dup;
assert(getopt(args, "paranoid+", &paranoid)); getopt(args, "paranoid+", &paranoid);
assert(paranoid == 5, to!(string)(paranoid)); assert(paranoid == 5, to!(string)(paranoid));
string data = "file.dat"; string data = "file.dat";
@ -473,11 +477,11 @@ unittest
bool verbose = true; bool verbose = true;
args = (["program.name", "--length=5", args = (["program.name", "--length=5",
"--file", "dat.file", "--verbose"]).dup; "--file", "dat.file", "--verbose"]).dup;
assert(getopt( getopt(
args, args,
"length", &length, "length", &length,
"file", &data, "file", &data,
"verbose", &verbose)); "verbose", &verbose);
assert(args.length == 1); assert(args.length == 1);
assert(data == "dat.file"); assert(data == "dat.file");
assert(length == 5); assert(length == 5);
@ -487,14 +491,14 @@ unittest
string[] outputFiles; string[] outputFiles;
args = (["program.name", "--output=myfile.txt", args = (["program.name", "--output=myfile.txt",
"--output", "yourfile.txt"]).dup; "--output", "yourfile.txt"]).dup;
assert(getopt(args, "output", &outputFiles)); getopt(args, "output", &outputFiles);
assert(outputFiles.length == 2 assert(outputFiles.length == 2
&& outputFiles[0] == "myfile.txt" && outputFiles[0] == "myfile.txt"); && outputFiles[0] == "myfile.txt" && outputFiles[0] == "myfile.txt");
args = (["program.name", "--tune=alpha=0.5", args = (["program.name", "--tune=alpha=0.5",
"--tune", "beta=0.6"]).dup; "--tune", "beta=0.6"]).dup;
double[string] tuningParms; double[string] tuningParms;
assert(getopt(args, "tune", &tuningParms)); getopt(args, "tune", &tuningParms);
assert(args.length == 1); assert(args.length == 1);
assert(tuningParms.length == 2); assert(tuningParms.length == 2);
assert(tuningParms["alpha"] == 0.5); assert(tuningParms["alpha"] == 0.5);
@ -514,10 +518,10 @@ unittest
} }
} }
args = (["program.name", "--quiet"]).dup; args = (["program.name", "--quiet"]).dup;
assert(getopt(args, "verbose", &myHandler, "quiet", &myHandler)); getopt(args, "verbose", &myHandler, "quiet", &myHandler);
assert(verbosityLevel == 0); assert(verbosityLevel == 0);
args = (["program.name", "--verbose"]).dup; args = (["program.name", "--verbose"]).dup;
assert(getopt(args, "verbose", &myHandler, "quiet", &myHandler)); getopt(args, "verbose", &myHandler, "quiet", &myHandler);
assert(verbosityLevel == 2); assert(verbosityLevel == 2);
verbosityLevel = 1; verbosityLevel = 1;
@ -527,15 +531,15 @@ unittest
verbosityLevel = 2; verbosityLevel = 2;
} }
args = (["program.name", "--verbose", "2"]).dup; args = (["program.name", "--verbose", "2"]).dup;
assert(getopt(args, "verbose", &myHandler2)); getopt(args, "verbose", &myHandler2);
assert(verbosityLevel == 2); assert(verbosityLevel == 2);
bool foo, bar; bool foo, bar;
args = (["program.name", "--foo", "--bAr"]).dup; args = (["program.name", "--foo", "--bAr"]).dup;
assert(getopt(args, getopt(args,
std.getopt.config.caseSensitive, std.getopt.config.caseSensitive,
std.getopt.config.passThrough, std.getopt.config.passThrough,
"foo", &foo, "foo", &foo,
"bar", &bar)); "bar", &bar);
assert(args[1] == "--bAr"); assert(args[1] == "--bAr");
} }

View file

@ -1946,11 +1946,7 @@ unittest
bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 0) bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 0)
{ {
static if (isArray!(T)) { static if (isArray!(T)) {
<<<<<<< .mine
invariant n = lhs.length; invariant n = lhs.length;
=======
auto n = lhs.length;
>>>>>>> .r582
static if (isArray!(U)) { static if (isArray!(U)) {
// Two arrays // Two arrays
assert(n == rhs.length); assert(n == rhs.length);

View file

@ -11,7 +11,7 @@ WIKI = Phobos/StdNumeric
Author: Author:
Andrei Alexandrescu $(WEB erdani.org, Andrei Alexandrescu)
*/ */
/* /*
@ -52,7 +52,7 @@ Example:
float f(float x) { float f(float x) {
return cos(x) - x*x*x; return cos(x) - x*x*x;
} }
final x = secantMethod(&f, 0f, 1f); auto x = secantMethod(&f, 0f, 1f);
assert(approxEqual(x, 0.865474)); assert(approxEqual(x, 0.865474));
---- ----
*/ */
@ -79,7 +79,7 @@ unittest
float f(float x) { float f(float x) {
return cos(x) - x*x*x; return cos(x) - x*x*x;
} }
auto x = secantMethod!(f)(0f, 1f); invariant x = secantMethod!(f)(0f, 1f);
assert(approxEqual(x, 0.865474)); assert(approxEqual(x, 0.865474));
} }

View file

@ -1,20 +1,24 @@
// Written in the D programming language. // 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&uuml;hne, $(WEB erdani.org, Andrei Alexandrescu)
*
* Macros: * Macros:
* WIKI = Phobos/StdPath * WIKI = Phobos/StdPath
* Copyright: * Copyright:
* Placed into public domain. * Placed into public domain.
* www.digitalmars.com * 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; module std.path;

View file

@ -37,7 +37,7 @@ integers and real numbers have been implemented.
Author: Author:
Andrei Alexandrescu $(WEB erdani.org, Andrei Alexandrescu)
Credits: Credits:
@ -181,7 +181,7 @@ struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m)
UIntType next() UIntType next()
{ {
static if (m) static if (m)
_x = (cast(ulong) a * _x + c) % m; _x = cast(UIntType) ((cast(ulong) a * _x + c) % m);
else else
_x = a * _x + c; _x = a * _x + c;
return _x; return _x;
@ -334,6 +334,7 @@ struct MersenneTwisterEngine(
} }
for (mti = 1; mti < n; ++mti) { for (mti = 1; mti < n; ++mti) {
mt[mti] = mt[mti] =
cast(UIntType)
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> (w - 2))) + mti); (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> (w - 2))) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */ /* In the previous versions, MSBs of the seed affect */
@ -367,15 +368,18 @@ struct MersenneTwisterEngine(
for (; kk < n - m; ++kk) for (; kk < n - m; ++kk)
{ {
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask); 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) for (; kk < n - 1; ++kk)
{ {
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask); 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); 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; mti = 0;
} }
@ -388,7 +392,7 @@ struct MersenneTwisterEngine(
y ^= (y << temperingT) & temperingC; y ^= (y << temperingT) & temperingC;
y ^= (y >> temperingL); y ^= (y >> temperingL);
return y; return cast(UIntType) y;
} }
/** /**
@ -442,7 +446,7 @@ unittest
for the minutiae of the method being used. for the minutiae of the method being used.
*/ */
typedef Mt19937 Random; alias Mt19937 Random;
/** /**
A "good" seed for initializing random number engines. Initializing 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); Random gen(unpredictableSeed);
// Generate an integer in [0, 1024] // 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) // 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) alias typeof(return) Result;
(ref UniformRandomNumberGenerator gen, T a, T b) auto dist = UniformDistribution!(Result, leftLim, rightLim)(a, b);
{
auto dist = UniformDistribution!(T, leftLim, rightLim)(a, b);
return dist.next(gen); return dist.next(gen);
} }
}
unittest unittest
{ {
auto gen = Mt19937(unpredictableSeed); auto gen = Mt19937(unpredictableSeed);
auto a = uniform!(int)(gen, 0, 1024); auto a = uniform(gen, 0, 1024);
assert(0 <= a && a <= 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)); 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) foreach (i; 0 .. array.length)
{ {
// generate a random number i .. n // 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]); swap(array[i], array[which]);
} }
} }

View file

@ -25,11 +25,13 @@
*/ */
/********************************************** /**********************************************
* $(LINK2 http://www.digitalmars.com/ctg/regular.html, Regular expressions) * $(LINK2 http://www.digitalmars.com/ctg/regular.html, Regular
* are a powerful method of string pattern matching. * expressions) are a powerful method of string pattern matching. The
* The regular expression * regular expression language used in this library is the same as
* language used is the same as that commonly used, however, some of the very * that commonly used, however, some of the very advanced forms may
* advanced forms may behave slightly differently. * 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. * std.regexp is designed to work only with valid UTF strings as input.
* To validate untrusted input, use std.utf.validate(). * To validate untrusted input, use std.utf.validate().

View file

@ -10,6 +10,12 @@
* Standard I/O functions that extend $(B std.c.stdio). * Standard I/O functions that extend $(B std.c.stdio).
* $(B std.c.stdio) is $(D_PARAM public)ally imported when importing * $(B std.c.stdio) is $(D_PARAM public)ally imported when importing
* $(B std.stdio). * $(B std.stdio).
*
* Authors:
*
* $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
Alexandrescu)
*
* Macros: * Macros:
* WIKI=Phobos/StdStdio * WIKI=Phobos/StdStdio
*/ */
@ -241,6 +247,9 @@ void write(T...)(T args)
static const first = 0; static const first = 0;
} }
writef(target, "", args[first .. $]); writef(target, "", args[first .. $]);
static if (args.length && is(typeof(args[$ - 1]) : dchar)) {
if (args[$ - 1] == '\n') fflush(target);
}
} }
unittest unittest
@ -1231,7 +1240,7 @@ struct chunks
// if (fileName.length && fclose(f)) // if (fileName.length && fclose(f))
// StdioException("Could not close file `"~fileName~"'"); // StdioException("Could not close file `"~fileName~"'");
// } // }
const maxStackSize = 500 * 1024; const maxStackSize = 1024 * 16;
ubyte[] buffer = void; ubyte[] buffer = void;
if (size < maxStackSize) if (size < maxStackSize)
buffer = (cast(ubyte*) alloca(size))[0 .. size]; buffer = (cast(ubyte*) alloca(size))[0 .. size];
@ -1247,7 +1256,7 @@ struct chunks
{ {
// error occured // error occured
if (!feof(f)) throw new StdioException(ferror(f)); if (!feof(f)) throw new StdioException(ferror(f));
if (!r) break; // done reading buffer.length = r;
} }
if ((result = dg(buffer)) != 0) break; if ((result = dg(buffer)) != 0) break;
} }

View file

@ -2,15 +2,17 @@
// Written in the D programming language. // 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? * Authors:
* 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 * $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei
* is it a modified copy of the input string? The D array convention is Alexandrescu)
* "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.
* *
* Macros: * Macros:
* WIKI = Phobos/StdString * WIKI = Phobos/StdString
@ -1607,9 +1609,9 @@ bool startsWith(A1, A2)(A1 longer, A2 shorter)
if (longer[i] != e) return false; if (longer[i] != e) return false;
} }
} }
}
return true; return true;
} }
}
unittest unittest
{ {
@ -1697,9 +1699,9 @@ bool endsWith(A1, A2)(A1 longer, A2 shorter)
if (shorter[i] != e) return false; if (shorter[i] != e) return false;
} }
} }
}
return true; return true;
} }
}
unittest unittest
{ {

View file

@ -821,6 +821,8 @@ class Thread
static Thread[] getAll() static Thread[] getAll()
{ {
synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim]; synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
// @@@BUG1819@@@
return null;
} }
void pause() void pause()

View file

@ -1,23 +1,20 @@
// Written in the D programming language. // Written in the D programming language.
/** /**
* Templates with which to extract information about * Templates with which to extract information about
* types at compile time. * types at compile time.
* *
* Authors:
*
* $(WEB digitalmars.com, Walter Bright), Tomasz Stachowiak ($(D
* isExpressionTuple)), $(WEB erdani.org, Andrei Alexandrescu)
*
* Macros: * Macros:
* WIKI = Phobos/StdTraits * WIKI = Phobos/StdTraits
* Copyright: * Copyright:
* Public Domain * Public Domain
*/ */
/*
* Authors:
* Walter Bright, Digital Mars, www.digitalmars.com
* Tomasz Stachowiak (isExpressionTuple)
* Andrei Alexandrescu, www.erdani.org
*/
module std.traits; module std.traits;
import std.typetuple; import std.typetuple;
@ -119,12 +116,348 @@ template ParameterTypeTuple(dg)
template FieldTypeTuple(S) 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; alias typeof(S.tupleof) FieldTypeTuple;
else 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 * 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 unittest
{ {
interface I1 {} interface I1 {}
interface I2 {} 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 B2 : B1, I1 {}
class B3 : B2, I2 {} class B3 : B2, I2 {}
alias BaseClassesTuple!(B3) TL; alias InterfacesTuple!(B3) TL;
assert(TL.length == 3); //
assert(is (TL[0] == B2)); assert(TL.length == 2);
assert(is (TL[1] == B1)); assert(is (TL[0] == I2));
assert(is (TL[2] == Object)); assert(is (TL[1] == I1));
} }
/** /**
@ -251,22 +634,24 @@ template TransitiveBaseTypeTuple(T)
alias TypeTuple!() TransitiveBaseTypeTuple; alias TypeTuple!() TransitiveBaseTypeTuple;
else else
alias TypeTuple!(BaseClassesTuple!(T), alias TypeTuple!(BaseClassesTuple!(T),
BaseTypeTuple!(T)[1 .. $]) InterfacesTuple!(T))
TransitiveBaseTypeTuple; TransitiveBaseTypeTuple;
} }
unittest unittest
{ {
interface I1 {} interface I1 {}
interface I2 {}
class B1 {} class B1 {}
class B2 : B1 {} class B2 : B1, I1, I2 {}
class B3 : B2, I1 {} class B3 : B2, I1 {}
alias TransitiveBaseTypeTuple!(B3) TL; alias TransitiveBaseTypeTuple!(B3) TL;
assert(TL.length == 4); assert(TL.length == 5);
assert(is (TL[0] == B2)); assert(is (TL[0] == B2));
assert(is (TL[1] == B1)); assert(is (TL[1] == B1));
assert(is (TL[2] == Object)); assert(is (TL[2] == Object));
assert(is (TL[3] == I1)); assert(is (TL[3] == I1));
assert(is (TL[4] == I2));
assert(TransitiveBaseTypeTuple!(Object).length == 0); assert(TransitiveBaseTypeTuple!(Object).length == 0);
} }