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

@ -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

View file

@ -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]));
}

View file

@ -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);
}

View file

@ -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.

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,
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)) {

View file

@ -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);
// }

View file

@ -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+", &paranoid);
getopt(args, "paranoid+", &paranoid);
---------
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+", &paranoid));
getopt(args, "paranoid+", &paranoid);
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");
}

View file

@ -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);

View file

@ -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));
}

View file

@ -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&uuml;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;

View file

@ -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]);
}
}

View file

@ -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().

View file

@ -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;
}

View file

@ -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

View file

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

View file

@ -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);
}