Initial merge of candidate to trunk for r459:513

This commit is contained in:
Brad Roberts 2007-11-27 20:28:40 +00:00
parent 0e9836f3cb
commit 09916d399a
24 changed files with 3629 additions and 1110 deletions

View file

@ -102,13 +102,14 @@ INTERNAL_GC_EXTRAFILES = \
internal/gc/win32.mak \ internal/gc/win32.mak \
internal/gc/linux.mak internal/gc/linux.mak
STD_MODULES = array asserterror base64 bind bitarray boxer compiler contracts \ STD_MODULES = algorithm array asserterror base64 bind bitarray \
conv cover cpuid cstream ctype date dateparse demangle file format gc \ bitmanip boxer compiler contracts conv cover cpuid cstream \
getopt hiddenfunc intrinsic loader math math2 md5 metastrings mmfile \ ctype date dateparse demangle file format functional gc getopt \
moduleinit openrj outbuffer outofmemory path perf process random \ hiddenfunc intrinsic loader math math2 md5 metastrings mmfile \
regexp signals slist socket socketstream stdint stdio stream string \ moduleinit numeric openrj outbuffer outofmemory path perf \
switcherr syserror system thread traits typetuple uni uri utf variant \ process random regexp signals socket socketstream stdint stdio \
zip zlib stream string switcherr syserror system thread traits typecons \
typetuple uni uri utf variant zip zlib
STD_MODULES_NOTBUILT = stdarg STD_MODULES_NOTBUILT = stdarg
STD_C_MODULES = stdarg stdio STD_C_MODULES = stdarg stdio

View file

@ -111,9 +111,11 @@ NAVIGATION_PHOBOS=
) )
<h2><a href="phobos.html#std" title="D standard modules">std</a></h2> <h2><a href="phobos.html#std" title="D standard modules">std</a></h2>
$(UL $(UL
$(LI <a href="std_algorithm.html" title="General-purpose algorithms">std.algorithm</a>)
$(LI <a href="std_base64.html" title="Encode/decode base64 format">std.base64</a>) $(LI <a href="std_base64.html" title="Encode/decode base64 format">std.base64</a>)
$(LI <a href="std_bind.html" title="Function argument binding">std.bind</a>) $(LI <a href="std_bind.html" title="Function argument binding">std.bind</a>)
$(LI <a href="std_bitarray.html" title="Arrays of bits">std.bitarray</a>) $(LI <a href="std_bitarray.html" title="Arrays of bits">std.bitarray</a>)
$(LI <a href="std_bitmanip.html" title="Bit-level manipulation">std.bitmanip</a>)
$(LI <a href="std_boxer.html" title="Box/unbox types">std.boxer</a>) $(LI <a href="std_boxer.html" title="Box/unbox types">std.boxer</a>)
$(LI <a href="std_compiler.html" title="Information about the D compiler implementation">std.compiler</a>) $(LI <a href="std_compiler.html" title="Information about the D compiler implementation">std.compiler</a>)
$(LI <a href="std_contracts.html" title="Think assert">std.contracts</a>) $(LI <a href="std_contracts.html" title="Think assert">std.contracts</a>)
@ -132,6 +134,7 @@ NAVIGATION_PHOBOS=
$(LI <a href="std_md5.html" title="Compute MD5 digests">std.md5</a>) $(LI <a href="std_md5.html" title="Compute MD5 digests">std.md5</a>)
$(LI <a href="std_metastrings.html" title="Metaprogramming with strings">std.metastrings</a>) $(LI <a href="std_metastrings.html" title="Metaprogramming with strings">std.metastrings</a>)
$(LI <a href="std_mmfile.html" title="Memory mapped files">std.mmfile</a>) $(LI <a href="std_mmfile.html" title="Memory mapped files">std.mmfile</a>)
$(LI <a href="std_numeric.html" title="Numeric algorithms">std.numeric</a>)
$(LI <a href="std_openrj.html" title="Basic database">std.openrj</a>) $(LI <a href="std_openrj.html" title="Basic database">std.openrj</a>)
$(LI <a href="std_outbuffer.html" title="Assemble data into an array of bytes">std.outbuffer</a>) $(LI <a href="std_outbuffer.html" title="Assemble data into an array of bytes">std.outbuffer</a>)
$(LI <a href="std_outofmemory.html" title="Out of memory exception">std.outofmemory</a>) $(LI <a href="std_outofmemory.html" title="Out of memory exception">std.outofmemory</a>)
@ -150,6 +153,7 @@ NAVIGATION_PHOBOS=
$(LI <a href="std_system.html" title="Inquire about the CPU, operating system">std.system</a>) $(LI <a href="std_system.html" title="Inquire about the CPU, operating system">std.system</a>)
$(LI <a href="std_thread.html" title="Thread operations">std.thread</a>) $(LI <a href="std_thread.html" title="Thread operations">std.thread</a>)
$(LI <a href="std_traits.html" title="Type traits">std.traits</a>) $(LI <a href="std_traits.html" title="Type traits">std.traits</a>)
$(LI <a href="std_typecons.html" title="Type constructors">std.typecons</a>)
$(LI <a href="std_typetuple.html" title="Type tuples">std.typetuple</a>) $(LI <a href="std_typetuple.html" title="Type tuples">std.typetuple</a>)
$(LI <a href="std_uni.html" title="Unicode classification">std.uni</a>) $(LI <a href="std_uni.html" title="Unicode classification">std.uni</a>)
$(LI <a href="std_uri.html" title="Encode and decode Uniform Resource Identifiers (URIs)">std.uri</a>) $(LI <a href="std_uri.html" title="Encode and decode Uniform Resource Identifiers (URIs)">std.uri</a>)

439
std/algorithm.d Normal file
View file

@ -0,0 +1,439 @@
// Written in the D programming language.
/**
This module is a port of a growing fragment of the $(D_PARAM
algorithm) header in Alexander Stepanov's
$(LINK2 http://www.sgi.com/tech/stl/,Standard Template Library).
Macros:
WIKI = Phobos/StdAlgorithm
Author:
Andrei Alexandrescu
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Andrei Alexandrescu, www.erdani.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module std.algorithm;
private import std.stdio;
private import std.math;
private import std.random;
private import std.date;
private import std.functional;
/* The iterator-related part below is undocumented and might
* change in future releases. Do NOT rely on it.
*/
template IteratorType(T : U[], U)
{
alias U* IteratorType;
}
template ElementType(T : U[], U)
{
alias U ElementType;
}
IteratorType!(T[]) begin(T)(T[] range)
{
return range.ptr;
}
ElementType!(T[]) front(T)(T[] range)
{
assert(range.length);
return *range.ptr;
}
bool isEmpty(T)(T[] range)
{
return !range.length;
}
IteratorType!(T[]) end(T)(T[] range)
{
return range.ptr + range.length;
}
void next(T)(ref T[] range)
{
range = range.ptr[1 .. range.length];;
}
IteratorType!(R) adjacentFind(R, E)(R range)
{
if (range.isEmpty()) return range.end();
auto result = range.begin();
range.next();
if (range.isEmpty()) return range.end();
for (; !range.isEmpty(); range.next())
{
auto next = range.begin();
if (*result == *next) return result;
result = next;
}
return range.end();
}
IteratorType!(Range) find(Range, E)(Range haystack, E needle)
{
ElementType!(Range) e;
for (; !isEmpty(haystack); next(haystack))
{
if (front(haystack) == needle) break;
}
return begin(haystack);
}
unittest
{
int[] a = ([ 1, 2, 3 ]).dup;
assert(find(a, 5) == a.ptr + a.length);
assert(find(a, 2) == &a[1]);
}
/**
Swaps $(D_PARAM lhs) and $(D_PARAM rhs).
*/
void swap(T)(ref T lhs, ref T rhs)
{
final t = lhs;
lhs = rhs;
rhs = t;
}
/**
Implements C.A.R. Hoare's
$(LINK2 http://en.wikipedia.org/wiki/Selection_algorithm#Partition-based_general_selection_algorithm,
partition) algorithm. Specifically, reorders the range [$(D_PARAM
left), $(D_PARAM right)$(RPAREN) such that everything strictly smaller
(according to the predicate $(D_PARAM compare)) than $(D_PARAM *mid)
is to the left of the returned pointer, and everything else is at the
right of the returned pointer.
Precondition:
$(D_PARAM left == mid && mid == right
||
left <= mid && mid < right).
Returns:
If $(D_PARAM left == right), returns $(D_PARAM left). Otherwise,
return a value $(D_PARAM p) such that the following three conditions
are simultaneously true:
$(OL
$(LI $(D_PARAM *p == *mid))
$(LI $(D_PARAM compare(*p1, *p)) for all $(D_PARAM p1) in [$(D_PARAM
left), $(D_PARAM p)$(RPAREN))
$(LI $(D_PARAM !compare(*p2, *p)) for all $(D_PARAM p2) in [$(D_PARAM p),
$(D_PARAM right)$(RPAREN)))
Example:
----
auto a = [3, 3, 2].dup;
p = partition!(less)(a.ptr, a.ptr, a.ptr + a.length);
assert(p == a.ptr + 1 && a == [2, 3, 3]);
----
*/
template partition(alias compare)
{
///
T partition(T)(T left, T mid, T right)
{
if (left == right) return left;
assert(left <= mid && mid < right);
auto pivot = *mid;
--right;
swap(*mid, *right); // Move pivot to end
auto result = left;
for (auto i = left; i != right; ++i) {
if (!compare(*i, pivot)) continue;
swap(*result, *i);
++result;
}
swap(*right, *result); // Move pivot to its final place
assert(*result == pivot);
return result;
}
}
unittest
{
int[] a = null;
auto p = partition!(less)(a.ptr, a.ptr, a.ptr + a.length);
assert(p is null);
a = [2].dup;
p = partition!(less)(a.ptr, a.ptr, a.ptr + a.length);
assert(p == a.ptr);
a = [2, 2].dup;
p = partition!(less)(a.ptr, a.ptr, a.ptr + a.length);
assert(p == a.ptr);
p = partition!(less)(a.ptr, a.ptr + 1, a.ptr + a.length);
assert(p == a.ptr);
a = [3, 3, 2].dup;
p = partition!(less)(a.ptr, a.ptr, a.ptr + a.length);
assert(p == a.ptr + 1);
}
/**
Reorders the range [$(D_PARAM b), $(D_PARAM e)$(RPAREN) such that
$(D_PARAM nth) points to the element that would fall there if the
range were fully sorted. Effectively, it finds the nth smallest
(according to $(D_PARAM compare)) element in the range [$(D_PARAM b),
$(D_PARAM e)$(RPAREN).
Example:
----
auto v = ([ 25, 7, 9, 2, 0, 5, 21 ]).dup;
auto n = 4;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 9);
----
*/
template nthElement(alias compare)
{
///
void nthElement(T)(T b, T nth, T e)
{
assert(b <= nth && nth < e);
for (;;) {
auto pivot = b + (e - b) / 2;
pivot = partition!(compare)(b, pivot, e);
if (pivot == nth) return;
if (pivot < nth) b = pivot + 1;
else e = pivot;
}
}
}
unittest
{
scope(failure) writeln(stderr, "Failure testing algorithm");
auto v = ([ 25, 7, 9, 2, 0, 5, 21 ]).dup;
auto n = 4;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 9);
//
v = ([3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]).dup;
n = 3;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 3);
//
v = ([3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]).dup;
n = 1;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 2);
//
v = ([3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]).dup;
n = v.length - 1;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 7);
//
v = ([3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]).dup;
n = 0;
nthElement!(less)(v.ptr, v.ptr + n, v.ptr + v.length);
assert(v[n] == 1);
}
/**
Reverses $(D_PARAM range) in-place.
*/
void reverse(T)(T range)
{
auto len = range.length;
final limit = len / 2;
--len;
for (uint i = 0; i != limit; ++i)
{
final t = range[i];
range[i] = range[len - i];
range[len - i] = t;
}
}
unittest
{
int[] range = null;
reverse(range);
range = [ 1 ].dup;
reverse(range);
assert(range == [1]);
range = [1, 2].dup;
reverse(range);
assert(range == [2, 1]);
range = [1, 2, 3].dup;
reverse(range);
assert(range == [3, 2, 1]);
}
/**
Sorts a random-access range according to predicate $(D_PARAM comp),
which must be a function name.
Example:
----
int[] array = ([ 1, 2, 3, 4 ]).dup;
sort!(greater)(array);
assert(array == [ 4, 3, 2, 1 ]);
bool myComp(int x, int y) { return x < y; }
sort!(myComp)(array);
assert(array == [ 1, 2, 3, 4 ]);
----
*/
template sort(alias comp)
{
void sort(Range)(Range r)
{
static if (is(typeof(comp(*begin(r), *end(r))) == bool))
{
sortImpl!(comp)(begin(r), end(r));
assert(isSorted!(comp)(r));
}
else
{
static assert(false, typeof(&comp).stringof);
}
}
}
/**
Sorts a random-access range according to predicate $(D_PARAM comp),
expressed as a string. The string can use the names "a" and "b" for
the two elements being compared.
Example:
----
int[] array = ([ 1, 2, 3, 4 ]).dup;
sort!("a > b")(array);
assert(array == [ 4, 3, 2, 1 ]);
----
*/
template sort(string comp)
{
void sort(Range)(Range r)
{
alias typeof(*begin(r)) ElementType;
static ElementType a, b;
alias typeof(mixin(comp)) ResultType;
static ResultType compFn(ElementType a, ElementType b)
{
return mixin(comp);
}
.sort!(compFn)(r);
}
}
unittest
{
// sort using delegate
int a[] = new int[100];
auto rnd = Random(getUTCtime);
foreach (ref e; a) {
e = uniform!(int)(rnd, -100, 100);
}
int i = 0;
bool greater2(int a, int b) { return a + i > b + i; }
bool delegate(int, int) greater = &greater2;
sort!(greater)(a);
assert(isSorted!(greater)(a));
// sort using string
sort!("a < b")(a);
assert(isSorted!(less)(a));
// sort using function; all elements equal
foreach (ref e; a) {
e = 5;
}
sort!(less)(a);
assert(isSorted!(less)(a));
// sort using ternary predicate
//sort!("b - a")(a);
//assert(isSorted!(less)(a));
}
/*private*/ template getPivot(alias compare)
{
Iter getPivot(Iter)(Iter b, Iter e)
{
final r = b + (e - b) / 2;
return r;
}
}
/*private*/ template sortImpl(alias comp)
{
void sortImpl(Iter)(Iter b, Iter e)
{
while (e - b > 1)
{
auto m = partition!(comp)(b, getPivot!(comp)(b, e), e);
assert(b <= m && m < e);
.sortImpl!(comp)(b, m);
b = ++m;
}
}
}
/**
Checks whether a random-access range is sorted according to the
comparison operation $(D_PARAM comp).
Example:
----
int[] arr = ([4, 3, 2, 1]).dup;
assert(!isSorted!(less)(arr));
sort!(less)(arr);
assert(isSorted!(less)(arr));
----
*/
template isSorted(alias comp)
{
bool isSorted(Range)(Range r)
{
auto b = begin(r), e = end(r);
if (e - b <= 1) return true;
auto next = b + 1;
for (; next < e; ++b, ++next) {
if (comp(*next, *b)) return false;
}
return true;
}
}

View file

@ -1,941 +1,14 @@
// Written in the D programming language // Written in the D programming language
/*********************** /***********************
* Scheduled for deprecation. Use $(LINK2
* std_bitmanip.html,std.bitmanip) instead.
*
* Macros: * Macros:
* WIKI = StdBitarray * WIKI = StdBitarray
*/ */
module std.bitarray; module std.bitarray;
public import std.bitmanip;
//debug = bitarray; // uncomment to turn on debugging printf's pragma(msg, "You may want to import std.bitmanip instead of std.bitarray");
private import std.intrinsic;
/**
* An array of bits.
*/
struct BitArray
{
size_t len;
uint* ptr;
size_t dim()
{
return (len + 31) / 32;
}
size_t length()
{
return len;
}
void length(size_t newlen)
{
if (newlen != len)
{
size_t olddim = dim();
size_t newdim = (newlen + 31) / 32;
if (newdim != olddim)
{
// Create a fake array so we can use D's realloc machinery
uint[] b = ptr[0 .. olddim];
b.length = newdim; // realloc
ptr = b.ptr;
if (newdim & 31)
{ // Set any pad bits to 0
ptr[newdim - 1] &= ~(~0 << (newdim & 31));
}
}
len = newlen;
}
}
/**********************************************
* Support for [$(I index)] operation for BitArray.
*/
bool opIndex(size_t i)
in
{
assert(i < len);
}
body
{
return cast(bool)bt(ptr, i);
}
/** ditto */
bool opIndexAssign(bool b, size_t i)
in
{
assert(i < len);
}
body
{
if (b)
bts(ptr, i);
else
btr(ptr, i);
return b;
}
/**********************************************
* Support for array.dup property for BitArray.
*/
BitArray dup()
{
BitArray ba;
uint[] b = ptr[0 .. dim].dup;
ba.len = len;
ba.ptr = b.ptr;
return ba;
}
unittest
{
BitArray a;
BitArray b;
int i;
debug(bitarray) printf("BitArray.dup.unittest\n");
a.length = 3;
a[0] = 1; a[1] = 0; a[2] = 1;
b = a.dup;
assert(b.length == 3);
for (i = 0; i < 3; i++)
{ debug(bitarray) printf("b[%d] = %d\n", i, b[i]);
assert(b[i] == (((i ^ 1) & 1) ? true : false));
}
}
/**********************************************
* Support for foreach loops for BitArray.
*/
int opApply(int delegate(inout bool) dg)
{
int result;
for (size_t i = 0; i < len; i++)
{ bool b = opIndex(i);
result = dg(b);
(*this)[i] = b;
if (result)
break;
}
return result;
}
/** ditto */
int opApply(int delegate(inout size_t, inout bool) dg)
{
int result;
for (size_t i = 0; i < len; i++)
{ bool b = opIndex(i);
result = dg(i, b);
(*this)[i] = b;
if (result)
break;
}
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opApply unittest\n");
static bool[] ba = [1,0,1];
BitArray a; a.init(ba);
int i;
foreach (b;a)
{
switch (i)
{ case 0: assert(b == true); break;
case 1: assert(b == false); break;
case 2: assert(b == true); break;
default: assert(0);
}
i++;
}
foreach (j,b;a)
{
switch (j)
{ case 0: assert(b == true); break;
case 1: assert(b == false); break;
case 2: assert(b == true); break;
default: assert(0);
}
}
}
/**********************************************
* Support for array.reverse property for BitArray.
*/
BitArray reverse()
out (result)
{
assert(result == *this);
}
body
{
if (len >= 2)
{
bool t;
size_t lo, hi;
lo = 0;
hi = len - 1;
for (; lo < hi; lo++, hi--)
{
t = (*this)[lo];
(*this)[lo] = (*this)[hi];
(*this)[hi] = t;
}
}
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.reverse.unittest\n");
BitArray b;
static bool[5] data = [1,0,1,1,0];
int i;
b.init(data);
b.reverse;
for (i = 0; i < data.length; i++)
{
assert(b[i] == data[4 - i]);
}
}
/**********************************************
* Support for array.sort property for BitArray.
*/
BitArray sort()
out (result)
{
assert(result == *this);
}
body
{
if (len >= 2)
{
size_t lo, hi;
lo = 0;
hi = len - 1;
while (1)
{
while (1)
{
if (lo >= hi)
goto Ldone;
if ((*this)[lo] == true)
break;
lo++;
}
while (1)
{
if (lo >= hi)
goto Ldone;
if ((*this)[hi] == false)
break;
hi--;
}
(*this)[lo] = false;
(*this)[hi] = true;
lo++;
hi--;
}
Ldone:
;
}
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.sort.unittest\n");
static uint x = 0b1100011000;
static BitArray ba = { 10, &x };
ba.sort;
for (size_t i = 0; i < 6; i++)
assert(ba[i] == false);
for (size_t i = 6; i < 10; i++)
assert(ba[i] == true);
}
/***************************************
* Support for operators == and != for bit arrays.
*/
int opEquals(BitArray a2)
{ int i;
if (this.length != a2.length)
return 0; // not equal
byte *p1 = cast(byte*)this.ptr;
byte *p2 = cast(byte*)a2.ptr;
uint n = this.length / 8;
for (i = 0; i < n; i++)
{
if (p1[i] != p2[i])
return 0; // not equal
}
ubyte mask;
n = this.length & 7;
mask = cast(ubyte)((1 << n) - 1);
//printf("i = %d, n = %d, mask = %x, %x, %x\n", i, n, mask, p1[i], p2[i]);
return (mask == 0) || (p1[i] & mask) == (p2[i] & mask);
}
unittest
{
debug(bitarray) printf("BitArray.opEquals unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1];
static bool[] bc = [1,0,1,0,1,0,1];
static bool[] bd = [1,0,1,1,1];
static bool[] be = [1,0,1,0,1];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c; c.init(bc);
BitArray d; d.init(bd);
BitArray e; e.init(be);
assert(a != b);
assert(a != c);
assert(a != d);
assert(a == e);
}
/***************************************
* Implement comparison operators.
*/
int opCmp(BitArray a2)
{
uint len;
uint i;
len = this.length;
if (a2.length < len)
len = a2.length;
ubyte* p1 = cast(ubyte*)this.ptr;
ubyte* p2 = cast(ubyte*)a2.ptr;
uint n = len / 8;
for (i = 0; i < n; i++)
{
if (p1[i] != p2[i])
break; // not equal
}
for (uint j = i * 8; j < len; j++)
{ ubyte mask = cast(ubyte)(1 << j);
int c;
c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask);
if (c)
return c;
}
return cast(int)this.len - cast(int)a2.length;
}
unittest
{
debug(bitarray) printf("BitArray.opCmp unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1];
static bool[] bc = [1,0,1,0,1,0,1];
static bool[] bd = [1,0,1,1,1];
static bool[] be = [1,0,1,0,1];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c; c.init(bc);
BitArray d; d.init(bd);
BitArray e; e.init(be);
assert(a > b);
assert(a >= b);
assert(a < c);
assert(a <= c);
assert(a < d);
assert(a <= d);
assert(a == e);
assert(a <= e);
assert(a >= e);
}
/***************************************
* Set BitArray to contents of ba[]
*/
void init(bool[] ba)
{
length = ba.length;
foreach (i, b; ba)
{
(*this)[i] = b;
}
}
/***************************************
* Map BitArray onto v[], with numbits being the number of bits
* in the array. Does not copy the data.
*
* This is the inverse of opCast.
*/
void init(void[] v, size_t numbits)
in
{
assert(numbits <= v.length * 8);
assert((v.length & 3) == 0);
}
body
{
ptr = cast(uint*)v.ptr;
len = numbits;
}
unittest
{
debug(bitarray) printf("BitArray.init unittest\n");
static bool[] ba = [1,0,1,0,1];
BitArray a; a.init(ba);
BitArray b;
void[] v;
v = cast(void[])a;
b.init(v, a.length);
assert(b[0] == 1);
assert(b[1] == 0);
assert(b[2] == 1);
assert(b[3] == 0);
assert(b[4] == 1);
a[0] = 0;
assert(b[0] == 0);
assert(a == b);
}
/***************************************
* Convert to void[].
*/
void[] opCast()
{
return cast(void[])ptr[0 .. dim];
}
unittest
{
debug(bitarray) printf("BitArray.opCast unittest\n");
static bool[] ba = [1,0,1,0,1];
BitArray a; a.init(ba);
void[] v = cast(void[])a;
assert(v.length == a.dim * uint.sizeof);
}
/***************************************
* Support for unary operator ~ for bit arrays.
*/
BitArray opCom()
{
auto dim = this.dim();
BitArray result;
result.length = len;
for (size_t i = 0; i < dim; i++)
result.ptr[i] = ~this.ptr[i];
if (len & 31)
result.ptr[dim - 1] &= ~(~0 << (len & 31));
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opCom unittest\n");
static bool[] ba = [1,0,1,0,1];
BitArray a; a.init(ba);
BitArray b = ~a;
assert(b[0] == 0);
assert(b[1] == 1);
assert(b[2] == 0);
assert(b[3] == 1);
assert(b[4] == 0);
}
/***************************************
* Support for binary operator & for bit arrays.
*/
BitArray opAnd(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
BitArray result;
result.length = len;
for (size_t i = 0; i < dim; i++)
result.ptr[i] = this.ptr[i] & e2.ptr[i];
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opAnd unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c = a & b;
assert(c[0] == 1);
assert(c[1] == 0);
assert(c[2] == 1);
assert(c[3] == 0);
assert(c[4] == 0);
}
/***************************************
* Support for binary operator | for bit arrays.
*/
BitArray opOr(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
BitArray result;
result.length = len;
for (size_t i = 0; i < dim; i++)
result.ptr[i] = this.ptr[i] | e2.ptr[i];
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opOr unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c = a | b;
assert(c[0] == 1);
assert(c[1] == 0);
assert(c[2] == 1);
assert(c[3] == 1);
assert(c[4] == 1);
}
/***************************************
* Support for binary operator ^ for bit arrays.
*/
BitArray opXor(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
BitArray result;
result.length = len;
for (size_t i = 0; i < dim; i++)
result.ptr[i] = this.ptr[i] ^ e2.ptr[i];
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opXor unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c = a ^ b;
assert(c[0] == 0);
assert(c[1] == 0);
assert(c[2] == 0);
assert(c[3] == 1);
assert(c[4] == 1);
}
/***************************************
* Support for binary operator - for bit arrays.
*
* $(I a - b) for BitArrays means the same thing as $(I a &amp; ~b).
*/
BitArray opSub(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
BitArray result;
result.length = len;
for (size_t i = 0; i < dim; i++)
result.ptr[i] = this.ptr[i] & ~e2.ptr[i];
return result;
}
unittest
{
debug(bitarray) printf("BitArray.opSub unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c = a - b;
assert(c[0] == 0);
assert(c[1] == 0);
assert(c[2] == 0);
assert(c[3] == 0);
assert(c[4] == 1);
}
/***************************************
* Support for operator &= bit arrays.
*/
BitArray opAndAssign(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
for (size_t i = 0; i < dim; i++)
ptr[i] &= e2.ptr[i];
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opAndAssign unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
a &= b;
assert(a[0] == 1);
assert(a[1] == 0);
assert(a[2] == 1);
assert(a[3] == 0);
assert(a[4] == 0);
}
/***************************************
* Support for operator |= for bit arrays.
*/
BitArray opOrAssign(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
for (size_t i = 0; i < dim; i++)
ptr[i] |= e2.ptr[i];
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opOrAssign unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
a |= b;
assert(a[0] == 1);
assert(a[1] == 0);
assert(a[2] == 1);
assert(a[3] == 1);
assert(a[4] == 1);
}
/***************************************
* Support for operator ^= for bit arrays.
*/
BitArray opXorAssign(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
for (size_t i = 0; i < dim; i++)
ptr[i] ^= e2.ptr[i];
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opXorAssign unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
a ^= b;
assert(a[0] == 0);
assert(a[1] == 0);
assert(a[2] == 0);
assert(a[3] == 1);
assert(a[4] == 1);
}
/***************************************
* Support for operator -= for bit arrays.
*
* $(I a -= b) for BitArrays means the same thing as $(I a &amp;= ~b).
*/
BitArray opSubAssign(BitArray e2)
in
{
assert(len == e2.length);
}
body
{
auto dim = this.dim();
for (size_t i = 0; i < dim; i++)
ptr[i] &= ~e2.ptr[i];
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opSubAssign unittest\n");
static bool[] ba = [1,0,1,0,1];
static bool[] bb = [1,0,1,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
a -= b;
assert(a[0] == 0);
assert(a[1] == 0);
assert(a[2] == 0);
assert(a[3] == 0);
assert(a[4] == 1);
}
/***************************************
* Support for operator ~= for bit arrays.
*/
BitArray opCatAssign(bool b)
{
length = len + 1;
(*this)[len - 1] = b;
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opCatAssign unittest\n");
static bool[] ba = [1,0,1,0,1];
BitArray a; a.init(ba);
BitArray b;
b = (a ~= true);
assert(a[0] == 1);
assert(a[1] == 0);
assert(a[2] == 1);
assert(a[3] == 0);
assert(a[4] == 1);
assert(a[5] == 1);
assert(b == a);
}
/***************************************
* ditto
*/
BitArray opCatAssign(BitArray b)
{
auto istart = len;
length = len + b.length;
for (auto i = istart; i < len; i++)
(*this)[i] = b[i - istart];
return *this;
}
unittest
{
debug(bitarray) printf("BitArray.opCatAssign unittest\n");
static bool[] ba = [1,0];
static bool[] bb = [0,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c;
c = (a ~= b);
assert(a.length == 5);
assert(a[0] == 1);
assert(a[1] == 0);
assert(a[2] == 0);
assert(a[3] == 1);
assert(a[4] == 0);
assert(c == a);
}
/***************************************
* Support for binary operator ~ for bit arrays.
*/
BitArray opCat(bool b)
{
BitArray r;
r = this.dup;
r.length = len + 1;
r[len] = b;
return r;
}
/** ditto */
BitArray opCat_r(bool b)
{
BitArray r;
r.length = len + 1;
r[0] = b;
for (size_t i = 0; i < len; i++)
r[1 + i] = (*this)[i];
return r;
}
/** ditto */
BitArray opCat(BitArray b)
{
BitArray r;
r = this.dup();
r ~= b;
return r;
}
unittest
{
debug(bitarray) printf("BitArray.opCat unittest\n");
static bool[] ba = [1,0];
static bool[] bb = [0,1,0];
BitArray a; a.init(ba);
BitArray b; b.init(bb);
BitArray c;
c = (a ~ b);
assert(c.length == 5);
assert(c[0] == 1);
assert(c[1] == 0);
assert(c[2] == 0);
assert(c[3] == 1);
assert(c[4] == 0);
c = (a ~ true);
assert(c.length == 3);
assert(c[0] == 1);
assert(c[1] == 0);
assert(c[2] == 1);
c = (false ~ a);
assert(c.length == 3);
assert(c[0] == 0);
assert(c[1] == 1);
assert(c[2] == 0);
}
}

1187
std/bitmanip.d Normal file

File diff suppressed because it is too large Load diff

View file

@ -1103,6 +1103,7 @@ enum
export HANDLE GetCurrentThread(); export HANDLE GetCurrentThread();
export BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); export BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime);
export HANDLE GetCurrentProcess(); export HANDLE GetCurrentProcess();
export DWORD GetCurrentProcessId();
export BOOL DuplicateHandle (HANDLE sourceProcess, HANDLE sourceThread, export BOOL DuplicateHandle (HANDLE sourceProcess, HANDLE sourceThread,
HANDLE targetProcessHandle, HANDLE *targetHandle, DWORD access, HANDLE targetProcessHandle, HANDLE *targetHandle, DWORD access,
BOOL inheritHandle, DWORD options); BOOL inheritHandle, DWORD options);

View file

@ -28,6 +28,7 @@
* ---- * ----
* *
* Author: * Author:
*
* Andrei Alexandrescu * Andrei Alexandrescu
* *
* Credits: * Credits:
@ -36,6 +37,7 @@
*/ */
module std.contracts; module std.contracts;
private import std.conv;
/* /*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
@ -70,12 +72,42 @@ module std.contracts;
* ---- * ----
*/ */
T enforce(T)(T value, lazy string msg = "") T enforce(T)(T value, lazy string msg = "Enforcement error ")
{ {
if (value) return value; if (value) return value;
throw new Exception(msg); throw new Exception(msg);
} }
/**
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws
* $(D_PARAM ex).
* Example:
* ----
* auto f = enforce(fopen("data.txt"));
* auto line = readln(f);
* enforce(line.length, new IOException); // expect a non-empty line
* ----
*/
T enforce(T)(T value, lazy Exception ex)
{
if (value) return value;
throw ex();
}
unittest
{
enforce(true, new Exception("this should not be thrown"));
try
{
enforce(false, new Exception("this should be thrown"));
assert(false);
}
catch (Exception e)
{
}
}
/** /**
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws * If $(D_PARAM value) is nonzero, returns it. Otherwise, throws
* $(D_PARAM new E(msg)). * $(D_PARAM new E(msg)).

View file

@ -57,9 +57,11 @@ class ConvError : Error
} }
} }
private void conv_error(string s) private void conv_error(S, T)(S source)
{ {
throw new ConvError(s); throw new ConvError(cast(string)
("Can't convert value `"~to!(string)(source)~"' of type "
~S.stringof~" to type "~T.stringof));
} }
/** /**
@ -348,7 +350,13 @@ private T numberToNumber(S, T)(S value) {
private T parseString(T)(const(char)[] v) private T parseString(T)(const(char)[] v)
{ {
scope(exit) { if (v.length) conv_error(v.idup); } scope(exit)
{
if (v.length)
{
conv_error!(const(char)[], T)(v);
}
}
return parse!(T)(v); return parse!(T)(v);
} }
@ -667,7 +675,10 @@ private N parseIntegral(S, N)(ref S s)
alias uint N1; alias uint N1;
auto v = parseIntegral!(S, N1)(s); auto v = parseIntegral!(S, N1)(s);
auto result = cast(N) v; auto result = cast(N) v;
if (result != v) conv_error(to!(string)(s)); if (result != v)
{
conv_error!(S, N)(s);
}
return result; return result;
} }
else else
@ -724,7 +735,7 @@ private N parseIntegral(S, N)(ref S s)
Loverflow: Loverflow:
conv_overflow(to!(string)(s)); conv_overflow(to!(string)(s));
Lerr: Lerr:
conv_error(to!(string)(s)); conv_error!(S, N)(s);
return 0; return 0;
} }
} }
@ -736,7 +747,7 @@ private N parseIntegral(S, N)(ref S s)
int toInt(string s) int toInt(string s)
{ {
scope(exit) { if (s.length) conv_error(s); } scope(exit) { if (s.length) conv_error!(string, int)(s); }
return parseIntegral!(string, int)(s); return parseIntegral!(string, int)(s);
} }
@ -811,7 +822,7 @@ unittest
*/ */
uint toUint(string s) uint toUint(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, uint)(s);
return parseIntegral!(string, uint)(s); return parseIntegral!(string, uint)(s);
} }
@ -880,7 +891,7 @@ unittest
long toLong(string s) long toLong(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, long)(s);
return parseIntegral!(string, long)(s); return parseIntegral!(string, long)(s);
} }
@ -961,7 +972,7 @@ unittest
ulong toUlong(string s) ulong toUlong(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, ulong)(s);
return parseIntegral!(string, ulong)(s); return parseIntegral!(string, ulong)(s);
} }
@ -1037,7 +1048,7 @@ unittest
short toShort(string s) short toShort(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, short)(s);
return parseIntegral!(string, short)(s); return parseIntegral!(string, short)(s);
} }
@ -1112,7 +1123,7 @@ unittest
ushort toUshort(string s) ushort toUshort(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, ushort)(s);
return parseIntegral!(string, ushort)(s); return parseIntegral!(string, ushort)(s);
} }
@ -1182,7 +1193,7 @@ unittest
byte toByte(string s) byte toByte(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, byte)(s);
return parseIntegral!(string, byte)(s); return parseIntegral!(string, byte)(s);
} }
@ -1257,7 +1268,7 @@ unittest
ubyte toUbyte(string s) ubyte toUbyte(string s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(string, ubyte)(s);
return parseIntegral!(string, ubyte)(s); return parseIntegral!(string, ubyte)(s);
} }
@ -1327,7 +1338,7 @@ unittest
float toFloat(Char)(Char[] s) float toFloat(Char)(Char[] s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(Char[], float)(s);
return parseFloating!(Char[], float)(s); return parseFloating!(Char[], float)(s);
} }
@ -1341,6 +1352,12 @@ F parseFloating(S : S[], F)(ref S[] s)
if (std.ctype.isspace(*sz)) if (std.ctype.isspace(*sz))
goto Lerr; goto Lerr;
// issue 1589
version (Windows)
{
if (icmp(s, "nan") == 0) return F.nan;
}
// BUG: should set __locale_decpoint to "." for DMC // BUG: should set __locale_decpoint to "." for DMC
setErrno(0); setErrno(0);
@ -1364,7 +1381,7 @@ F parseFloating(S : S[], F)(ref S[] s)
s = s[endptr - sz .. $]; s = s[endptr - sz .. $];
return f; return f;
Lerr: Lerr:
conv_error(to!(string)(s) ~ " not representable as a " ~ F.stringof); conv_error!(S[], F)(s);
assert(0); assert(0);
} }
@ -1373,6 +1390,8 @@ unittest
debug( conv ) writefln( "conv.toFloat.unittest" ); debug( conv ) writefln( "conv.toFloat.unittest" );
float f; float f;
f = toFloat( "nAn" );
assert(isnan(f));
f = toFloat( "123" ); f = toFloat( "123" );
assert( f == 123f ); assert( f == 123f );
f = toFloat( "+123" ); f = toFloat( "+123" );
@ -1418,7 +1437,7 @@ unittest
double toDouble(Char)(Char[] s) double toDouble(Char)(Char[] s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(Char[], double)(s);
return parseFloating!(Char[], double)(s); return parseFloating!(Char[], double)(s);
} }
@ -1474,7 +1493,7 @@ unittest
*/ */
real toReal(Char)(Char[] s) real toReal(Char)(Char[] s)
{ {
scope(exit) if (s.length) conv_error(s); scope(exit) if (s.length) conv_error!(Char[], real)(s);
return parseFloating!(Char[], real)(s); return parseFloating!(Char[], real)(s);
} }
@ -1907,9 +1926,7 @@ unittest
* Grammar: * Grammar:
* ['+'|'-'] string floating-point digit {digit} * ['+'|'-'] string floating-point digit {digit}
*/ */
// @@@ BUG IN COMPILER: writing "in string s" instead of "string s" changes its private bool getComplexStrings(in string s, out string s1, out string s2)
// type from invariant(char)[] to const(char)[] !!!
private bool getComplexStrings(string s, out string s1, out string s2)
{ {
int len = s.length; int len = s.length;
@ -1953,7 +1970,7 @@ private bool getComplexStrings(string s, out string s1, out string s2)
Lerr: Lerr:
// Display the original string in the error message. // Display the original string in the error message.
conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\"" throw new ConvError("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\""
~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\""); ~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\"");
return 0; return 0;
} }

View file

@ -38,7 +38,7 @@ module std.cover;
private import std.stdio; private import std.stdio;
private import std.file; private import std.file;
private import std.bitarray; private import std.bitmanip;
private private
{ {

View file

@ -1591,6 +1591,8 @@ struct DirIterator
int opApply(D)(D dg) int opApply(D)(D dg)
{ {
int result = 0; int result = 0;
string[] worklist = [ pathname ]; // used only in breadth-first traversal
bool callback(DirEntry* de) bool callback(DirEntry* de)
{ {
switch (mode) switch (mode)
@ -1602,7 +1604,7 @@ struct DirIterator
result = doIt(dg, de); result = doIt(dg, de);
if (!result && de.isdir) if (!result && de.isdir)
{ {
listdir(de.name, &callback); worklist ~= de.name;
} }
break; break;
default: default:
@ -1618,8 +1620,15 @@ struct DirIterator
break; break;
} }
return result == 0; return result == 0;
} }
listdir(pathname, &callback);
// consume the worklist
while (worklist.length)
{
auto listThis = worklist[$ - 1];
worklist.length = worklist.length - 1;
listdir(listThis, &callback);
}
return result; return result;
} }
} }

View file

@ -47,6 +47,8 @@ import std.conv;
import std.traits; import std.traits;
import std.typetuple; import std.typetuple;
import std.stdio; // for debugging only import std.stdio; // for debugging only
import std.contracts;
import std.system;
version (Windows) version (Windows)
{ {
@ -77,8 +79,6 @@ else
*/ */
class FormatError : Error class FormatError : Error
{ {
private:
this() this()
{ {
super("std.format"); super("std.format");
@ -1773,6 +1773,24 @@ unittest
*/ */
private void formatIntegral(Writer, D)(ref Writer w, D arg, FormatInfo f) private void formatIntegral(Writer, D)(ref Writer w, D arg, FormatInfo f)
{ {
if (f.spec == 'r')
{
// raw write, skip all else and write the thing
auto begin = cast(const char*) &arg;
if (std.system.endian == Endian.LittleEndian && f.flPlus
|| std.system.endian == Endian.BigEndian && f.flDash)
{
// must swap bytes
foreach_reverse (i; 0 .. arg.sizeof)
w.putchar(begin[i]);
}
else
{
foreach (i; 0 .. arg.sizeof)
w.putchar(begin[i]);
}
return;
}
if (f.precision == f.precision.max - 1) if (f.precision == f.precision.max - 1)
{ {
// default precision for integrals is 1 // default precision for integrals is 1
@ -1885,34 +1903,52 @@ private void formatIntegral(Writer, D)(ref Writer w, D arg, FormatInfo f)
*/ */
private void formatFloat(Writer, D)(ref Writer w, D obj, FormatInfo f) private void formatFloat(Writer, D)(ref Writer w, D obj, FormatInfo f)
{ {
if (std.string.find("fgFGaAeEs", f.spec) < 0) { if (f.spec == 'r')
throw new FormatError("floating"); {
} // raw write, skip all else and write the thing
if (f.spec == 's') f.spec = 'g'; auto begin = cast(const char*) &obj;
char sprintfSpec[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/ if (std.system.endian == Endian.LittleEndian && f.flPlus
+ 1 /*\0*/] = void; || std.system.endian == Endian.BigEndian && f.flDash)
sprintfSpec[0] = '%'; {
uint i = 1; // must swap bytes
if (f.flDash) sprintfSpec[i++] = '-'; foreach_reverse (i; 0 .. obj.sizeof)
if (f.flPlus) sprintfSpec[i++] = '+'; w.putchar(begin[i]);
if (f.flZero) sprintfSpec[i++] = '0'; }
if (f.flSpace) sprintfSpec[i++] = ' '; else
if (f.flHash) sprintfSpec[i++] = '#'; {
sprintfSpec[i .. i + 3] = "*.*"; foreach (i; 0 .. obj.sizeof)
i += 3; w.putchar(begin[i]);
if (is(D == real)) sprintfSpec[i++] = 'L'; }
sprintfSpec[i++] = f.spec; return;
sprintfSpec[i] = 0; }
//writeln(sprintfSpec); if (std.string.find("fgFGaAeEs", f.spec) < 0) {
char[512] buf; throw new FormatError("floating");
final n = snprintf(buf.ptr, buf.length, }
sprintfSpec.ptr, if (f.spec == 's') f.spec = 'g';
f.width, char sprintfSpec[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/
// negative precision is same as no precision specified + 1 /*\0*/] = void;
f.precision == f.precision.max - 1 ? -1 : f.precision, sprintfSpec[0] = '%';
obj); uint i = 1;
if (n < 0) throw new FormatError("floating point formatting failure"); if (f.flDash) sprintfSpec[i++] = '-';
w.write(buf[0 .. strlen(buf.ptr)]); if (f.flPlus) sprintfSpec[i++] = '+';
if (f.flZero) sprintfSpec[i++] = '0';
if (f.flSpace) sprintfSpec[i++] = ' ';
if (f.flHash) sprintfSpec[i++] = '#';
sprintfSpec[i .. i + 3] = "*.*";
i += 3;
if (is(D == real)) sprintfSpec[i++] = 'L';
sprintfSpec[i++] = f.spec;
sprintfSpec[i] = 0;
//writeln(sprintfSpec);
char[512] buf;
final n = snprintf(buf.ptr, buf.length,
sprintfSpec.ptr,
f.width,
// negative precision is same as no precision specified
f.precision == f.precision.max - 1 ? -1 : f.precision,
obj);
if (n < 0) throw new FormatError("floating point formatting failure");
w.write(buf[0 .. strlen(buf.ptr)]);
} }
/* /*
@ -2005,21 +2041,28 @@ private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Fix for issue 1591
private int getNthInt(A...)(uint index, A args) private int getNthInt(A...)(uint index, A args)
{ {
foreach (i, arg; args) static if (A.length)
{ {
static if (is(typeof(arg) : long) || is(typeof(arg) : ulong)) if (index)
{ {
if (i != index) continue; return getNthInt(index - 1, args[1 .. $]);
return to!(int)(arg); }
static if (is(typeof(args[0]) : long) || is(typeof(arg) : ulong))
{
return to!(int)(args[0]);
} }
else else
{ {
if (i == index) break; throw new FormatError("int expected");
} }
} }
throw new FormatError("int expected"); else
{
throw new FormatError("int expected");
}
} }
/* (Not public yet.) /* (Not public yet.)
@ -2146,6 +2189,21 @@ void formattedWrite(Writer, F, A...)(ref Writer w, const(F)[] fmt, A args)
/* ======================== Unit Tests ====================================== */ /* ======================== Unit Tests ====================================== */
unittest
{
// testing raw writes
StringWriter!(char) w;
w.backend = null;
uint a = 0x02030405;
formattedWrite(w, "%+r", a);
assert(w.backend.length == 4 && w.backend[0] == 2 && w.backend[1] == 3
&& w.backend[2] == 4 && w.backend[3] == 5);
w.backend = null;
formattedWrite(w, "%-r", a);
assert(w.backend.length == 4 && w.backend[0] == 5 && w.backend[1] == 4
&& w.backend[2] == 3 && w.backend[3] == 2);
}
unittest unittest
{ {
// testing positional parameters // testing positional parameters

49
std/functional.d Normal file
View file

@ -0,0 +1,49 @@
// 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).
Macros:
WIKI = Phobos/StdFunctional
Author:
Andrei Alexandrescu
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Andrei Alexandrescu, www.erdani.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module std.functional;
/**
Predicate that returns $(D_PARAM a < b).
*/
bool less(T)(T a, T b) { return a < b; }
/**
Predicate that returns $(D_PARAM a > b).
*/
bool greater(T)(T a, T b) { return a > b; }

View file

@ -65,6 +65,7 @@ private import std.stdio;
private import std.c.stdio; private import std.c.stdio;
private import std.string; private import std.string;
private import std.c.math; private import std.c.math;
private import std.traits;
class NotImplemented : Error class NotImplemented : Error
{ {
@ -1429,10 +1430,32 @@ real nan(char[] tagp) { return std.c.math.nanl(toStringz(tagp)); }
*/ */
real nextafter(real x, real y) real nextafter(real x, real y)
{ {
version (linux) return std.c.math.nextafterl(x, y);
return std.c.math.nextafterl(x, y); }
else
throw new NotImplemented("nextafter"); /// ditto
float nextafter(float x, float y)
{
return std.c.math.nextafterf(x, y);
}
/// ditto
double nextafter(double x, double y)
{
return std.c.math.nextafter(x, y);
}
unittest
{
float a = 1;
double b = 2;
real c = 3;
assert(is(typeof(nextafter(a, a)) == float));
assert(is(typeof(nextafter(b, b)) == double));
assert(is(typeof(nextafter(c, c)) == real));
assert(nextafter(a, a.infinity) > a);
assert(nextafter(b, b.infinity) > b);
assert(nextafter(c, c.infinity) > c);
} }
//real nexttoward(real x, real y) { return std.c.math.nexttowardl(x, y); } //real nexttoward(real x, real y) { return std.c.math.nexttowardl(x, y); }
@ -1887,4 +1910,58 @@ unittest
assert( poly(x, pp) == (56.1L + (32.7L + 6L * x) * x) ); assert( poly(x, pp) == (56.1L + (32.7L + 6L * x) * x) );
} }
/**
Computes whether $(D lhs) is approximately equal to $(D rhs)
admitting a maximum relative difference $(D maxRelDiff) and a
maximum absolute difference $(D maxAbsDiff).
*/
bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 0)
{
static if (isArray!(T)) {
final n = lhs.length;
static if (isArray!(U)) {
// Two arrays
assert(n == rhs.length);
for (uint i = 0; i != n; ++i) {
if (!approxEqual(lhs[i], rhs[i], maxRelDiff, maxAbsDiff))
return false;
}
} else {
// lhs is array, rhs is number
for (uint i = 0; i != n; ++i) {
if (!approxEqual(lhs[i], rhs, maxRelDiff, maxAbsDiff))
return false;
}
}
return true;
} else {
static if (isArray!(U)) {
// lhs is number, rhs is array
return approxEqual(rhs, lhs, maxRelDiff);
} else {
// two numbers
//static assert(is(T : real) && is(U : real));
if (rhs == 0) {
return (lhs == 0 ? 0 : 1) <= maxRelDiff;
}
return fabs((lhs - rhs) / rhs) <= maxRelDiff
|| maxAbsDiff != 0 && fabs(lhs - rhs) < maxAbsDiff;
}
}
}
/**
Returns $(D approxEqual(lhs, rhs, 0.01)).
*/
bool approxEqual(T, U)(T lhs, U rhs) {
return approxEqual(lhs, rhs, 0.01);
}
unittest
{
assert(approxEqual(1.0, 1.0099));
assert(!approxEqual(1.0, 1.011));
float[] arr1 = [ 1.0, 2.0, 3.0 ];
double[] arr2 = [ 1.001, 1.999, 3 ];
assert(approxEqual(arr1, arr2));
}

View file

@ -74,18 +74,20 @@ template FormatString(const(char)[] F, A...)
template ToString(ulong U) template ToString(ulong U)
{ {
static if (U < 10) static if (U < 10)
const char[] ToString = "" ~ cast(char)(U + '0'); invariant char[] ToString = "" ~ cast(char)(U + '0');
else else
const char[] ToString = ToString!(U / 10) ~ ToString!(U % 10); invariant char[] ToString = ToString!(U / 10) ~ ToString!(U % 10);
} }
static assert(ToString!(1uL << 62) == "4611686018427387904");
/// ditto /// ditto
template ToString(long I) template ToString(long I)
{ {
static if (I < 0) static if (I < 0)
const char[] ToString = "-" ~ ToString!(cast(ulong)(-I)); invariant char[] ToString = "-" ~ ToString!(cast(ulong)(-I));
else else
const char[] ToString = ToString!(cast(ulong)I); invariant char[] ToString = ToString!(cast(ulong)I);
} }
static assert(ToString!(0x100000000) == "4294967296"); static assert(ToString!(0x100000000) == "4294967296");
@ -93,55 +95,55 @@ static assert(ToString!(0x100000000) == "4294967296");
/// ditto /// ditto
template ToString(uint U) template ToString(uint U)
{ {
const char[] ToString = ToString!(cast(ulong)U); invariant char[] ToString = ToString!(cast(ulong)U);
} }
/// ditto /// ditto
template ToString(int I) template ToString(int I)
{ {
const char[] ToString = ToString!(cast(long)I); invariant char[] ToString = ToString!(cast(long)I);
} }
/// ditto /// ditto
template ToString(ushort U) template ToString(ushort U)
{ {
const char[] ToString = ToString!(cast(ulong)U); invariant char[] ToString = ToString!(cast(ulong)U);
} }
/// ditto /// ditto
template ToString(short I) template ToString(short I)
{ {
const char[] ToString = ToString!(cast(long)I); invariant char[] ToString = ToString!(cast(long)I);
} }
/// ditto /// ditto
template ToString(ubyte U) template ToString(ubyte U)
{ {
const char[] ToString = ToString!(cast(ulong)U); invariant char[] ToString = ToString!(cast(ulong)U);
} }
/// ditto /// ditto
template ToString(byte I) template ToString(byte I)
{ {
const char[] ToString = ToString!(cast(long)I); invariant char[] ToString = ToString!(cast(long)I);
} }
/// ditto /// ditto
template ToString(bool B) template ToString(bool B)
{ {
const char[] ToString = B ? "true" : "false"; invariant char[] ToString = B ? "true" : "false";
} }
/// ditto /// ditto
template ToString(string S) template ToString(string S)
{ {
const char[] ToString = S; invariant char[] ToString = S;
} }
/// ditto /// ditto
template ToString(char C) template ToString(char C)
{ {
const char[] ToString = "" ~ C; invariant char[] ToString = "" ~ C;
} }
unittest unittest

85
std/numeric.d Normal file
View file

@ -0,0 +1,85 @@
// Written in the D programming language.
/**
This module is a port of a growing fragment of the $(D_PARAM numeric)
header in Alexander Stepanov's $(LINK2 http://sgi.com/tech/stl,
Standard Template Library), with a few additions.
Macros:
WIKI = Phobos/StdNumeric
Author:
Andrei Alexandrescu
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Andrei Alexandrescu, www.erdani.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module std.numeric;
import std.math;
import std.stdio;
/**
Implements the $(LINK2 http://tinyurl.com/2zb9yr,secant method) for
finding a root of the function $(D_PARAM f) starting from points
[xn_1, x_n] (ideally close to the root). $(D_PARAM Num) may be
$(D_PARAM float), $(D_PARAM double), or $(D_PARAM real).
Example:
----
float f(float x) {
return cos(x) - x*x*x;
}
final x = secantMethod(&f, 0f, 1f);
assert(approxEqual(x, 0.865474));
----
*/
template secantMethod(alias F)
{
Num secantMethod(Num)(Num xn_1, Num xn) {
auto fxn = F(xn_1), d = xn_1 - xn;
typeof(fxn) fxn_1;
xn = xn_1;
while (!approxEqual(d, 0) && isfinite(d)) {
xn_1 = xn;
xn -= d;
fxn_1 = fxn;
fxn = F(xn);
d *= -fxn / (fxn - fxn_1);
}
return xn;
}
}
unittest
{
scope(failure) writeln(stderr, "Failure testing secantMethod");
float f(float x) {
return cos(x) - x*x*x;
}
final x = secantMethod!(f)(0f, 1f);
assert(approxEqual(x, 0.865474));
}

View file

@ -23,6 +23,7 @@ module std.path;
//private import std.stdio; //private import std.stdio;
private import std.string; private import std.string;
private import std.file;
version(linux) version(linux)
{ {
@ -36,35 +37,35 @@ version(Windows)
/** String used to separate directory names in a path. Under /** String used to separate directory names in a path. Under
* Windows this is a backslash, under Linux a slash. */ * Windows this is a backslash, under Linux a slash. */
const char[1] sep = "\\"; invariant char[1] sep = "\\";
/** Alternate version of sep[] used in Windows (a slash). Under /** Alternate version of sep[] used in Windows (a slash). Under
* Linux this is empty. */ * Linux this is empty. */
const char[1] altsep = "/"; invariant char[1] altsep = "/";
/** Path separator string. A semi colon under Windows, a colon /** Path separator string. A semi colon under Windows, a colon
* under Linux. */ * under Linux. */
const char[1] pathsep = ";"; invariant char[1] pathsep = ";";
/** String used to separate lines, \r\n under Windows and \n /** String used to separate lines, \r\n under Windows and \n
* under Linux. */ * under Linux. */
const char[2] linesep = "\r\n"; /// String used to separate lines. invariant char[2] linesep = "\r\n"; /// String used to separate lines.
const char[1] curdir = "."; /// String representing the current directory. invariant char[1] curdir = "."; /// String representing the current directory.
const char[2] pardir = ".."; /// String representing the parent directory. invariant char[2] pardir = ".."; /// String representing the parent directory.
} }
version(linux) version(linux)
{ {
/** String used to separate directory names in a path. Under /** String used to separate directory names in a path. Under
* Windows this is a backslash, under Linux a slash. */ * Windows this is a backslash, under Linux a slash. */
const char[1] sep = "/"; invariant char[1] sep = "/";
/** Alternate version of sep[] used in Windows (a slash). Under /** Alternate version of sep[] used in Windows (a slash). Under
* Linux this is empty. */ * Linux this is empty. */
const char[0] altsep; invariant char[0] altsep;
/** Path separator string. A semi colon under Windows, a colon /** Path separator string. A semi colon under Windows, a colon
* under Linux. */ * under Linux. */
const char[1] pathsep = ":"; invariant char[1] pathsep = ":";
/** String used to separate lines, \r\n under Windows and \n /** String used to separate lines, \r\n under Windows and \n
* under Linux. */ * under Linux. */
const char[1] linesep = "\n"; invariant char[1] linesep = "\n";
const char[1] curdir = "."; /// String representing the current directory. invariant char[1] curdir = "."; /// String representing the current directory.
const char[2] pardir = ".."; /// String representing the parent directory. invariant char[2] pardir = ".."; /// String representing the parent directory.
} }
/***************************** /*****************************
@ -579,6 +580,52 @@ unittest
} }
} }
/**
* Converts a relative path into an absolute path. Currently only
* implemented on Linux.
*/
string rel2abs(string path)
{
version(windows)
{
static assert(false, "rel2abs not yet implemented on Windows");
}
if (!path.length) return null;
if (startsWith(path, sep) || altsep.length && startsWith(path, altsep))
{
return path;
}
auto myDir = getcwd();
if (path.startsWith(curdir))
{
auto p = path[curdir.length .. $];
if (p.startsWith(sep))
path = p[sep.length .. $];
else if (altsep.length && p.startsWith(altsep))
path = p[altsep.length .. $];
else if (!p.length)
path = null;
}
return myDir.endsWith(sep)
? myDir ~ path
: path.length ? myDir ~ sep ~ path : myDir;
}
unittest
{
version (linux)
{
auto myDir = getcwd();
scope(exit) std.file.chdir(myDir);
std.file.chdir("/");
assert(rel2abs(".") == "/", rel2abs("."));
assert(rel2abs("bin") == "/bin", rel2abs("bin"));
assert(rel2abs("./bin") == "/bin", rel2abs("./bin"));
std.file.chdir("bin");
assert(rel2abs(".") == "/bin", rel2abs("."));
}
}
/************************************* /*************************************
* Joins two path components. * Joins two path components.
* *

View file

@ -37,6 +37,10 @@ private import std.c.stdlib;
private import std.c.string; private import std.c.string;
private import std.string; private import std.string;
private import std.c.process; private import std.c.process;
version (Windows)
{
private import std.c.windows.windows:GetCurrentProcessId;
}
/** /**
* Execute command in a _command shell. * Execute command in a _command shell.
@ -247,6 +251,15 @@ else
} // version } // version
} }
version(linux)
{
alias std.c.process.getpid getpid;
}
else version (Windows)
{
alias std.c.windows.windows.GetCurrentProcessId getpid;
}
/* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */
version(MainTest) version(MainTest)
@ -285,3 +298,4 @@ version(MainTest)
} }
/* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */

View file

@ -1,18 +1,113 @@
// Written in the D programming language // Written in the D programming language
/** /**
* Macros: Facilities for random number generation. The old-style functions
* WIKI = Phobos/StdRandom $(D_PARAM rand_seed) and $(D_PARAM rand) will soon be deprecated as
*/ they rely on global state and as such are subjected to various
thread-related issues.
The new-style generator objects hold their own state so they are
immune of threading issues. The generators feature a number of
well-known and well-documented methods of generating random
numbers. An overall fast and reliable means to generate random
numbers is the $(D_PARAM Mt19937) generator, which derives its name
from "$(LINK2 http://math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,
Mersenne Twister) with a period of 2 to the power of 19937". In
memory-constrained situations,
$(LINK2 http://en.wikipedia.org/wiki/Linear_congruential_generator,
linear congruential) generators such as MinstdRand0 and MinstdRand
might be useful. The standard library provides an alias $(D_PARAM
Random) for whichever generator it finds the most fit for the
target environment.
Example:
----
Random gen;
// Generate a uniformly-distributed integer in the range [0, 15]
auto i = uniform!(int)(gen, 0, 15);
// Generate a uniformly-distributed real in the range [0, 100$(RPAREN)
auto r = uniform!(real)(gen, 0.0L, 100.0L);
----
In addition to random number generators, this module features
distributions, which skew a generator's output statistical
distribution in various ways. So far the uniform distribution for
integers and real numbers have been implemented.
Author:
Andrei Alexandrescu
Credits:
The entire random number library architecture is derived from the
excellent
$(LINK2 http://open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf,
C++0X) random number facility proposed by Jens Maurer and contrinuted
to by researchers at the Fermi laboratory.
Macros:
WIKI = Phobos/StdRandom
*/
// random.d // random.d
// www.digitalmars.com // www.digitalmars.com
module std.random; module std.random;
import std.stdio, std.math, std.c.time, std.traits, std.contracts, std.conv,
std.algorithm, std.process, std.date;
// Segments of the code in this file Copyright (c) 1997 by Rick Booth // Segments of the code in this file Copyright (c) 1997 by Rick Booth
// From "Inner Loops" by Rick Booth, Addison-Wesley // From "Inner Loops" by Rick Booth, Addison-Wesley
// Work derived from:
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
version (Win32) version (Win32)
{ {
extern(Windows) int QueryPerformanceCounter(ulong *count); extern(Windows) int QueryPerformanceCounter(ulong *count);
@ -23,6 +118,557 @@ version (linux)
private import std.c.linux.linux; private import std.c.linux.linux;
} }
/**
Linear Congruential generator.
*/
struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m)
{
/// Alias for the generated type $(D_PARAM UIntType).
alias UIntType ResultType;
static invariant
{
/// Does this generator have a fixed range? ($(D_PARAM true)).
bool hasFixedRange = true;
/// Lowest generated value.
ResultType min = ( c == 0 ? 1 : 0 );
/// Highest generated value.
ResultType max = m - 1;
/**
The parameters of this distribution. The random number is $(D_PARAM x =
(x * a + c) % m).
*/
UIntType
multiplier = a,
///ditto
increment = c,
///ditto
modulus = m;
}
static assert(isIntegral!(UIntType));
static assert(m == 0 || a < m);
static assert(m == 0 || c < m);
static assert(m == 0 ||
(cast(ulong)a * (m-1) + c) % m == (c < a ? c - a + m : c - a));
/**
Constructs a $(D_PARAM LinearCongruentialEngine) generator.
*/
static LinearCongruentialEngine opCall(UIntType x0 = 1)
{
LinearCongruentialEngine result;
result.seed(x0);
return result;
}
/**
(Re)seeds the generator.
*/
void seed(UIntType x0 = 1)
{
static if (c == 0)
{
enforce(x0, "Invalid (zero) seed for "
~LinearCongruentialEngine.stringof);
}
_x = modulus ? (x0 % modulus) : x0;
}
/**
Returns the next number in the random sequence.
*/
UIntType next()
{
static if (m)
_x = (cast(ulong) a * _x + c) % m;
else
_x = a * _x + c;
return _x;
}
/**
Discards next $(D_PARAM n) samples.
*/
void discard(ulong n)
{
while (n--) next;
}
/**
Compares against $(D_PARAM rhs) for equality.
*/
bool opEquals(LinearCongruentialEngine rhs)
{
return _x == rhs._x;
}
private UIntType _x = 1;
};
/**
Define $(D_PARAM LinearCongruentialEngine) generators with "good"
parameters.
Example:
----
// seed with a constant
auto rnd0 = MinstdRand0(1);
auto n = rnd0.next; // same for each run
// Seed with an unpredictable value
rnd0.seed(unpredictableSeed);
n = rnd0.next; // different across runs
----
*/
alias LinearCongruentialEngine!(uint, 16807, 0, 2147483647) MinstdRand0;
/// ditto
alias LinearCongruentialEngine!(uint, 48271, 0, 2147483647) MinstdRand;
unittest
{
// The correct numbers are taken from The Database of Integer Sequences
// http://www.research.att.com/~njas/sequences/eisBTfry00128.txt
auto checking0 = [
16807UL,282475249,1622650073,984943658,1144108930,470211272,
101027544,1457850878,1458777923,2007237709,823564440,1115438165,
1784484492,74243042,114807987,1137522503,1441282327,16531729,
823378840,143542612 ];
auto rnd0 = MinstdRand0(1);
foreach (e; checking0)
{
assert(rnd0.next == e);
}
// Test the 10000th invocation
// Correct value taken from:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
rnd0.seed;
rnd0.discard(9999);
assert(rnd0.next == 1043618065);
// Test MinstdRand
auto checking = [48271UL,182605794,1291394886,1914720637,2078669041,
407355683];
auto rnd = MinstdRand(1);
foreach (e; checking)
{
assert(rnd.next == e);
}
// Test the 10000th invocation
// Correct value taken from:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
rnd.seed;
rnd.discard(9999);
assert(rnd.next == 399268537);
}
/**
The $(LINK2 http://math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,
Mersenne Twister generator).
*/
struct MersenneTwisterEngine(
UIntType, size_t w, size_t n, size_t m, size_t r,
UIntType a, size_t u, size_t s,
UIntType b, size_t t,
UIntType c, size_t l)
{
/// Result type (an alias for $(D_PARAM UIntType)).
alias UIntType ResultType;
/**
Parameter for the generator.
*/
static invariant
{
size_t wordSize = w;
size_t stateSize = n;
size_t shiftSize = m;
size_t maskBits = r;
UIntType xorMask = a;
UIntType temperingU = u;
size_t temperingS = s;
UIntType temperingB = b;
size_t temperingT = t;
UIntType temperingC = c;
size_t temperingL = l;
}
/// Smallest generated value (0).
static invariant UIntType min = 0;
/// Largest generated value.
static invariant UIntType max =
w == UIntType.sizeof * 8 ? UIntType.max : (1u << w) - 1;
/// The default seed value.
static invariant UIntType defaultSeed = 5489u;
static assert(1 <= m && m <= n);
static assert(0 <= r && 0 <= u && 0 <= s && 0 <= t && 0 <= l);
static assert(r <= w && u <= w && s <= w && t <= w && l <= w);
static assert(0 <= a && 0 <= b && 0 <= c);
static assert(a <= max && b <= max && c <= max);
/**
Constructs a MersenneTwisterEngine object
*/
static MersenneTwisterEngine opCall(ResultType value)
{
MersenneTwisterEngine result;
result.seed(value);
return result;
}
/**
Constructs a MersenneTwisterEngine object
*/
void seed(ResultType value = defaultSeed)
{
static if (w == ResultType.sizeof * 8)
{
mt[0] = value;
}
else
{
static assert(max + 1 > 0);
mt[0] = value % (max + 1);
}
for (mti = 1; mti < n; ++mti) {
mt[mti] =
(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 */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= ResultType.max;
/* for >32 bit machines */
}
}
/**
Returns the next random value.
*/
uint next()
{
static invariant ResultType
upperMask = ~((cast(ResultType) 1u <<
(ResultType.sizeof * 8 - (w - r))) - 1),
lowerMask = (cast(ResultType) 1u << r) - 1;
ulong y = void;
static invariant ResultType mag01[2] = [0x0UL, a];
if (mti >= n)
{
/* generate N words at one time */
if (mti == n + 1) /* if init_genrand() has not been called, */
seed(5489UL); /* a default initial seed is used */
int kk = 0;
for (; kk < n - m; ++kk)
{
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask);
mt[kk] = mt[kk + m] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (; kk < n - 1; ++kk)
{
y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask);
mt[kk] = mt[kk + (m -n)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[n -1] & upperMask)|(mt[0] & lowerMask);
mt[n - 1] = mt[m - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> temperingU);
y ^= (y << temperingS) & temperingB;
y ^= (y << temperingT) & temperingC;
y ^= (y >> temperingL);
return y;
}
/**
Discards next $(D_PARAM n) samples.
*/
void discard(ulong n)
{
while (n--) next;
}
private ResultType mt[n];
private size_t mti = n + 1; /* means mt is not initialized */
}
/**
A $(D_PARAM MersenneTwisterEngine) instantiated with the parameters
of the original engine
$(LINK2 http://math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,MT19937),
generating uniformly-distributed 32-bit numbers with a period of 2
to the power of 19937. Recommended for random number generation
unless memory is severely restricted, in which case a $(D_PARAM
LinearCongruentialEngine) would be the generator of choice.
Example:
----
// seed with a constant
Mt19937 gen;
auto n = gen.next; // same for each run
// Seed with an unpredictable value
gen.seed(unpredictableSeed);
n = gen.next; // different across runs
----
*/
alias MersenneTwisterEngine!(uint, 32, 624, 397, 31, 0x9908b0df, 11, 7,
0x9d2c5680, 15, 0xefc60000, 18)
Mt19937;
unittest
{
Mt19937 gen;
gen.discard(9999);
assert(gen.next == 4123659995);
}
/**
The "default", "favorite", "suggested" random number generator on
the current platform. It is a typedef for one of the
previously-defined generators. You may want to use it if (1) you
need to generate some nice random numbers, and (2) you don't care
for the minutiae of the method being used.
*/
typedef Mt19937 Random;
/**
A "good" seed for initializing random number engines. Initializing
with $(D_PARAM unpredictableSeed) makes engines generate different
random number sequences every run.
Example:
----
auto rnd = Random(unpredictableSeed);
auto n = rnd.next;
...
----
*/
ulong unpredictableSeed()
{
return cast(ulong) (getpid ^ getUTCtime);
}
/**
Generates uniformly-distributed numbers within a range using an
external generator. The $(D_PARAM leftLim) and $(D_PARAM rightLim)
parameters control the shape of the interval (open vs. closed on
either side). The default interval is [a, b$(RPAREN).
Example:
----
auto a = new double[20];
Random gen;
auto rndIndex = UniformDistribution!(uint)(0, a.length);
auto rndValue = UniformDistribution!(double)(0, 1);
// Get a random index into the array
auto i = rndIndex.next(gen);
// Get a random probability, i.e., a real number in [0, 1$(RPAREN)
auto p = rndValue.next(gen);
// Assign that value to that array element
a[i] = p;
auto digits = UniformDistribution!(char, '[', ']')('0', '9');
auto percentages = UniformDistribution!(double, '$(LPAREN)', ']')(0.0, 100.0);
// Get a digit in ['0', '9']
auto digit = digits.next(gen);
// Get a number in $(LPAREN)0.0, 100.0]
auto p = percentages.next(gen);
----
*/
struct UniformDistribution(NumberType, char leftLim = '[', char rightLim = ')')
{
static assert((leftLim == '[' || leftLim == '(')
&& (rightLim == ']' || rightLim == ')'));
alias NumberType InputType;
alias NumberType ResultType;
/**
Constructs a $(D_PARAM UniformDistribution) able to generate
numbers in the interval [$(D_PARAM min), $(D_PARAM max)) if
$(D_PARAM closedRight) is $(D_PARAM false).
*/
static UniformDistribution opCall(NumberType a, NumberType b)
{
UniformDistribution result;
static if (leftLim == '(')
result._a = nextLarger(a);
else
result._a = a;
static if (rightLim == ')')
result._b = nextSmaller(b);
else
result._b = b;
enforce(result._a <= result._b,
"Invalid distribution range: " ~ leftLim ~ to!(string)(a)
~ ", " ~ to!(string)(b) ~ rightLim);
return result;
}
/**
Returns the smallest random value generated.
*/
ResultType a() { return leftLim == '[' ? _a : nextSmaller(_a); }
/**
Returns the largest random value generated.
*/
ResultType b() { return rightLim == ']' ? _b : nextLarger(_b); }
/**
Does nothing (provided for conformity with other distributions).
*/
void reset()
{
}
/**
Returns a random number using $(D_PARAM
UniformRandomNumberGenerator) as back-end.
*/
ResultType next(UniformRandomNumberGenerator)
(ref UniformRandomNumberGenerator urng)
{
static if (isIntegral!(NumberType))
{
auto myRange = _b - _a;
if (!myRange) return _a;
assert(urng.max - urng.min >= myRange,
"UniformIntGenerator.next not implemented for large ranges");
unsigned!(typeof((urng.max - urng.min + 1) / (myRange + 1)))
bucketSize = 1 + (urng.max - urng.min - myRange) / (myRange + 1);
assert(bucketSize, to!(string)(myRange));
ResultType r = void;
do
{
r = (urng.next - urng.min) / bucketSize;
}
while (r > myRange);
return _a + r;
}
else
{
return _a + (_b - _a) * cast(NumberType) (urng.next - urng.min)
/ (urng.max - urng.min);
}
}
private:
NumberType _a = 0, _b = NumberType.max;
static NumberType nextLarger(NumberType x)
{
static if (isIntegral!(NumberType))
return x + 1;
else
return nextafter(x, x.infinity);
}
static NumberType nextSmaller(NumberType x)
{
static if (isIntegral!(NumberType))
return x - 1;
else
return nextafter(x, -x.infinity);
}
}
unittest
{
MinstdRand0 gen;
auto rnd1 = UniformDistribution!(int)(0, 15);
foreach (i; 0 .. 20)
{
auto x = rnd1.next(gen);
assert(0 <= x && x <= 15);
//writeln(x);
}
}
unittest
{
MinstdRand0 gen;
foreach (i; 0 .. 20)
{
auto x = uniform!(double)(gen, 0., 15.);
assert(0 <= x && x <= 15);
//writeln(x);
}
}
/**
Convenience function that generates a number in an interval by
forwarding to $(D_PARAM UniformDistribution!(T, leftLim,
rightLim)(a, b).next).
Example:
----
Random gen(unpredictableSeed);
// Generate an integer in [0, 1024]
auto a = uniform!(int)(gen, 0, 1024);
// Generate a float in [0, 1$(RPAREN)
auto a = uniform!(float)(gen, 0.0f, 1.0f);
----
*/
template uniform(T, char leftLim = '[', char rightLim = ')')
{
T uniform(UniformRandomNumberGenerator)
(ref UniformRandomNumberGenerator gen, T a, T b)
{
auto dist = UniformDistribution!(T, leftLim, rightLim)(a, b);
return dist.next(gen);
}
}
unittest
{
auto gen = Mt19937(unpredictableSeed);
auto a = uniform!(int)(gen, 0, 1024);
assert(0 <= a && a <= 1024);
auto b = uniform!(float)(gen, 0.0f, 1.0f);
assert(0 <= b && b < 1, to!(string)(b));
}
/**
Shuffles elements of $(D_PARAM array) using $(D_PARAM r) as a
shuffler.
*/
void randomShuffle(T, SomeRandomGen)(T[] array, ref SomeRandomGen r)
{
foreach (i; 0 .. array.length)
{
// generate a random number i .. n
final which = i + uniform!(size_t)(r, 0u, array.length - i);
swap(array[i], array[which]);
}
}
unittest
{
auto a = ([ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]).dup;
auto b = a.dup;
Mt19937 gen;
randomShuffle(a, gen);
//assert(a == expectedA);
assert(a.sort == b.sort);
}
/* ===================== Random ========================= */ /* ===================== Random ========================= */
// BUG: not multithreaded // BUG: not multithreaded
@ -41,7 +687,10 @@ private uint index; // ith random number
Note: This is more random, but slower, than C's rand() function. Note: This is more random, but slower, than C's rand() function.
To use C's rand() instead, import std.c.stdlib. To use C's rand() instead, import std.c.stdlib.
*/
BUGS: Shares a global single state, not multithreaded.
SCHEDULED FOR DEPRECATION.
*/
void rand_seed(uint seed, uint index) void rand_seed(uint seed, uint index)
{ {
@ -51,7 +700,8 @@ void rand_seed(uint seed, uint index)
/** /**
* Get the next random number in sequence. * Get the next random number in sequence.
* BUGS: shares a global single state, not multithreaded * BUGS: Shares a global single state, not multithreaded.
* SCHEDULED FOR DEPRECATION.
*/ */
uint rand() uint rand()
@ -109,7 +759,7 @@ static this()
if (gettimeofday(&tv, null)) if (gettimeofday(&tv, null))
{ // Some error happened - try time() instead { // Some error happened - try time() instead
s = time(null); s = std.c.linux.linux.time(null);
} }
else else
{ {

View file

@ -143,7 +143,7 @@ private
import std.string; import std.string;
import std.ctype; import std.ctype;
import std.outbuffer; import std.outbuffer;
import std.bitarray; import std.bitmanip;
import std.utf; import std.utf;
} }
@ -152,11 +152,11 @@ private
* $(LINK2 http://www.regular-expressions.info/email.html, How to Find or Validate an Email Address)$(BR) * $(LINK2 http://www.regular-expressions.info/email.html, How to Find or Validate an Email Address)$(BR)
* $(LINK2 http://tools.ietf.org/html/rfc2822#section-3.4.1, RFC 2822 Internet Message Format) * $(LINK2 http://tools.ietf.org/html/rfc2822#section-3.4.1, RFC 2822 Internet Message Format)
*/ */
const char[] email = string email =
r"[a-zA-Z]([.]?([[a-zA-Z0-9_]-]+)*)?@([[a-zA-Z0-9_]\-_]+\.)+[a-zA-Z]{2,6}"; r"[a-zA-Z]([.]?([[a-zA-Z0-9_]-]+)*)?@([[a-zA-Z0-9_]\-_]+\.)+[a-zA-Z]{2,6}";
/** Regular expression to extract a _url */ /** Regular expression to extract a _url */
const char[] url = r"(([h|H][t|T]|[f|F])[t|T][p|P]([s|S]?)\:\/\/|~/|/)?([\w]+:\w+@)?(([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?)?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?([,]\w+)*((\?\w+=\w+)?(&\w+=\w+)*([,]\w*)*)?"; string url = r"(([h|H][t|T]|[f|F])[t|T][p|P]([s|S]?)\:\/\/|~/|/)?([\w]+:\w+@)?(([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?)?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?([,]\w+)*((\?\w+=\w+)?(&\w+=\w+)*([,]\w*)*)?";
/************************************ /************************************
* One of these gets thrown on compilation errors * One of these gets thrown on compilation errors
@ -237,7 +237,7 @@ unittest
* sub(s, "[ar]", * sub(s, "[ar]",
* delegate char[] (RegExp m) * delegate char[] (RegExp m)
* { * {
* return toupper(m.match(0)); * return toupper(m[0]);
* }, * },
* "g"); // result: StRAp A Rocket engine on A chicken. * "g"); // result: StRAp A Rocket engine on A chicken.
* --- * ---
@ -308,7 +308,7 @@ unittest
"[ar]", "[ar]",
delegate string (RegExp m) delegate string (RegExp m)
{ {
return std.string.toupper(m.match(0)); return std.string.toupper(m[0]);
}, },
"g"); "g");
assert(s == "StRAp A Rocket engine on A chicken."); assert(s == "StRAp A Rocket engine on A chicken.");
@ -316,21 +316,50 @@ unittest
/************************************************* /*************************************************
* Search s[] for first match with pattern[] with attributes[]. * Search $(D_PARAM s[]) for first match with $(D_PARAM pattern).
* Params: * Params:
* s = String to search. * s = String to search.
* pattern = Regular expression pattern. * pattern = Regular expression pattern.
* attributes = Regular expression attributes.
* Returns: * Returns:
* index into s[] of match if found, -1 if no match. * index into s[] of match if found, -1 if no match.
* Example: * Example:
* --- * ---
* auto s = "abcabcabab"; * auto s = "abcabcabab";
* std.regexp.find(s, "b"); // match, returns 1 * find(s, RegExp("b")); // match, returns 1
* std.regexp.find(s, "f"); // no match, returns -1 * find(s, RegExp("f")); // no match, returns -1
* --- * ---
*/ */
int find(string s, RegExp pattern)
{
return pattern.test(s)
? pattern.pmatch[0].rm_so
: -1;
}
unittest
{
debug(regexp) printf("regexp.find.unittest\n");
auto i = find("xabcy", RegExp("abc"));
assert(i == 1);
i = find("cba", RegExp("abc"));
assert(i == -1);
}
/**
Returns:
Same as $(D_PARAM find(s, RegExp(pattern, attributes))).
WARNING:
This function is scheduled for deprecation due to unnecessary
ambiguity with the homonym function in std.string. Instead of
$(D_PARAM std.regexp.find(s, p, a)), you may want to use $(D_PARAM
find(s, RegExp(p, a))).
*/
int find(string s, string pattern, string attributes = null) int find(string s, string pattern, string attributes = null)
{ {
int i = -1; int i = -1;
@ -354,24 +383,67 @@ unittest
assert(i == -1); assert(i == -1);
} }
/************************************************* /*************************************************
* Search s[] for last match with pattern[] with attributes[]. * Search $(D_PARAM s[]) for last match with $(D_PARAM pattern).
* Params: * Params:
* s = String to search. * s = String to search.
* pattern = Regular expression pattern. * pattern = Regular expression pattern.
* attributes = Regular expression attributes.
* Returns: * Returns:
* index into s[] of match if found, -1 if no match. * index into s[] of match if found, -1 if no match.
* Example: * Example:
* --- * ---
* auto s = "abcabcabab"; * auto s = "abcabcabab";
* std.regexp.find(s, "b"); // match, returns 9 * rfind(s, RegExp("b")); // match, returns 9
* std.regexp.find(s, "f"); // no match, returns -1 * rfind(s, RegExp("f")); // no match, returns -1
* --- * ---
*/ */
int rfind(string s, RegExp pattern)
{
int i = -1;
int lastindex = 0;
while (pattern.test(s, lastindex))
{ int eo = pattern.pmatch[0].rm_eo;
i = pattern.pmatch[0].rm_so;
if (lastindex == eo)
lastindex++; // always consume some source
else
lastindex = eo;
}
return i;
}
unittest
{
int i;
debug(regexp) printf("regexp.rfind.unittest\n");
i = rfind("abcdefcdef", RegExp("c"));
assert(i == 6);
i = rfind("abcdefcdef", RegExp("cd"));
assert(i == 6);
i = rfind("abcdefcdef", RegExp("x"));
assert(i == -1);
i = rfind("abcdefcdef", RegExp("xy"));
assert(i == -1);
i = rfind("abcdefcdef", RegExp(""));
assert(i == 10);
}
/*************************************************
Returns:
Same as $(D_PARAM rfind(s, RegExp(pattern, attributes))).
WARNING:
This function is scheduled for deprecation due to unnecessary
ambiguity with the homonym function in std.string. Instead of
$(D_PARAM std.regexp.rfind(s, p, a)), you may want to use $(D_PARAM
rfind(s, RegExp(p, a))).
*/
int rfind(string s, string pattern, string attributes = null) int rfind(string s, string pattern, string attributes = null)
{ {
int i = -1; int i = -1;
@ -410,16 +482,15 @@ unittest
/******************************************** /********************************************
* Split s[] into an array of strings, using the regular * Split s[] into an array of strings, using the regular
* expression pattern[] with attributes[] as the separator. * expression $(D_PARAM pattern) as the separator.
* Params: * Params:
* s = String to search. * s = String to search.
* pattern = Regular expression pattern. * pattern = Regular expression pattern.
* attributes = Regular expression attributes.
* Returns: * Returns:
* array of slices into s[] * array of slices into s[]
* Example: * Example:
* --- * ---
* foreach (s; split("abcabcabab", "C.", "i")) * foreach (s; split("abcabcabab", RegExp("C.", "i")))
* { * {
* writefln("s = '%s'", s); * writefln("s = '%s'", s);
* } * }
@ -430,6 +501,43 @@ unittest
* --- * ---
*/ */
string[] split(string s, RegExp pattern)
{
return pattern.split(s);
}
unittest
{
debug(regexp) printf("regexp.split.unittest()\n");
string[] result;
result = split("ab", RegExp("a*"));
assert(result.length == 2);
assert(result[0] == "");
assert(result[1] == "b");
foreach (i, s; split("abcabcabab", RegExp("C.", "i")))
{
//writefln("s[%d] = '%s'", i, s);
if (i == 0) assert(s == "ab");
else if (i == 1) assert(s == "b");
else if (i == 2) assert(s == "bab");
else assert(0);
}
}
/********************************************
Returns:
Same as $(D_PARAM split(s, RegExp(pattern, attributes))).
WARNING:
This function is scheduled for deprecation due to unnecessary
ambiguity with the homonym function in std.string. Instead of
$(D_PARAM std.regexp.split(s, p, a)), you may want to use $(D_PARAM
split(s, RegExp(p, a))).
*/
string[] split(string s, string pattern, string attributes = null) string[] split(string s, string pattern, string attributes = null)
{ {
auto r = new RegExp(pattern, attributes); auto r = new RegExp(pattern, attributes);
@ -475,7 +583,7 @@ unittest
* { * {
* if (auto m = std.regexp.search("abcdef", "c")) * if (auto m = std.regexp.search("abcdef", "c"))
* { * {
* writefln("%s[%s]%s", m.pre, m.match(0), m.post); * writefln("%s[%s]%s", m.pre, m[0], m.post);
* } * }
* } * }
* // Prints: * // Prints:
@ -486,13 +594,9 @@ unittest
RegExp search(string s, string pattern, string attributes = null) RegExp search(string s, string pattern, string attributes = null)
{ {
auto r = new RegExp(pattern, attributes); auto r = new RegExp(pattern, attributes);
if (!r.test(s))
if (r.test(s))
{
}
else
{ delete r; { delete r;
r = null; assert(r is null);
} }
return r; return r;
} }
@ -503,10 +607,10 @@ unittest
if (auto m = std.regexp.search("abcdef", "c()")) if (auto m = std.regexp.search("abcdef", "c()"))
{ {
auto result = std.string.format("%s[%s]%s", m.pre, m.match(0), m.post); auto result = std.string.format("%s[%s]%s", m.pre, m[0], m.post);
assert(result == "ab[c]def"); assert(result == "ab[c]def");
assert(m.match(1) == null); assert(m[1] == null);
assert(m.match(2) == null); assert(m[2] == null);
} }
else else
assert(0); assert(0);
@ -598,7 +702,7 @@ class RegExp
* { * {
* foreach(m; RegExp("ab").search("abcabcabab")) * foreach(m; RegExp("ab").search("abcabcabab"))
* { * {
* writefln("%s[%s]%s", m.pre, m.match(0), m.post); * writefln("%s[%s]%s", m.pre, m[0], m.post);
* } * }
* } * }
* // Prints: * // Prints:
@ -639,7 +743,7 @@ class RegExp
int i; int i;
foreach(m; RegExp("ab").search("abcabcabab")) foreach(m; RegExp("ab").search("abcabcabab"))
{ {
auto s = std.string.format("%s[%s]%s", m.pre, m.match(0), m.post); auto s = std.string.format("%s[%s]%s", m.pre, m[0], m.post);
if (i == 0) assert(s == "[ab]cabcabab"); if (i == 0) assert(s == "[ab]cabcabab");
else if (i == 1) assert(s == "abc[ab]cabab"); else if (i == 1) assert(s == "abc[ab]cabab");
else if (i == 2) assert(s == "abcabc[ab]ab"); else if (i == 2) assert(s == "abcabc[ab]ab");
@ -657,7 +761,7 @@ class RegExp
* if n is larger than the number of parenthesized subexpressions, * if n is larger than the number of parenthesized subexpressions,
* null is returned. * null is returned.
*/ */
public string match(size_t n) public string opIndex(size_t n)
{ {
if (n >= pmatch.length) if (n >= pmatch.length)
return null; return null;
@ -671,6 +775,20 @@ class RegExp
} }
} }
/**
Same as $(D_PARAM opIndex(n)).
WARNING:
Scheduled for deprecation due to confusion with overloaded
$(D_PARAM match(string)). Instead of $(D_PARAM regex.match(n))
you may want to use $(D_PARAM regex[n]).
*/
public string match(size_t n)
{
return this[n];
}
/******************* /*******************
* Return the slice of the input that precedes the matched substring. * Return the slice of the input that precedes the matched substring.
*/ */
@ -1255,6 +1373,21 @@ public int test(string s, int startindex)
return 0; // no match return 0; // no match
} }
/**
Returns whether string $(D_PARAM s) matches $(D_PARAM this).
*/
alias test opEquals;
// int opEquals(string s)
// {
// return test(s);
// }
unittest
{
assert("abc" == RegExp(".b."));
assert("abc" != RegExp(".b.."));
}
int chr(inout uint si, rchar c) int chr(inout uint si, rchar c)
{ {
for (; si < input.length; si++) for (; si < input.length; si++)
@ -3154,17 +3287,17 @@ unittest
auto m = search("aBC r s", `bc\x20r[\40]s`, "i"); auto m = search("aBC r s", `bc\x20r[\40]s`, "i");
assert(m.pre=="a"); assert(m.pre=="a");
assert(m.match(0)=="BC r s"); assert(m[0]=="BC r s");
auto m2 = search("7xxyxxx", `^\d([a-z]{2})\D\1`); auto m2 = search("7xxyxxx", `^\d([a-z]{2})\D\1`);
assert(m2.match(0)=="7xxyxx"); assert(m2[0]=="7xxyxx");
// Just check the parsing. // Just check the parsing.
auto m3 = search("dcbxx", `ca|b[\d\]\D\s\S\w-\W]`); auto m3 = search("dcbxx", `ca|b[\d\]\D\s\S\w-\W]`);
auto m4 = search("xy", `[^\ca-\xFa\r\n\b\f\t\v\0123]{2,485}$`); auto m4 = search("xy", `[^\ca-\xFa\r\n\b\f\t\v\0123]{2,485}$`);
auto m5 = search("xxx", `^^\r\n\b{13,}\f{4}\t\v\u02aF3a\w\W`); auto m5 = search("xxx", `^^\r\n\b{13,}\f{4}\t\v\u02aF3a\w\W`);
auto m6 = search("xxy", `.*y`); auto m6 = search("xxy", `.*y`);
assert(m6.match(0)=="xxy"); assert(m6[0]=="xxy");
auto m7 = search("QWDEfGH", "(ca|b|defg)+", "i"); auto m7 = search("QWDEfGH", "(ca|b|defg)+", "i");
assert(m7.match(0)=="DEfG"); assert(m7[0]=="DEfG");
auto m8 = search("dcbxx", `a?\B\s\S`); auto m8 = search("dcbxx", `a?\B\s\S`);
auto m9 = search("dcbxx", `[-w]`); auto m9 = search("dcbxx", `[-w]`);
auto m10 = search("dcbsfd", `aB[c-fW]dB|\d|\D|\u012356|\w|\W|\s|\S`, "i"); auto m10 = search("dcbsfd", `aB[c-fW]dB|\d|\D|\u012356|\w|\W|\s|\S`, "i");

View file

@ -28,7 +28,8 @@ import std.c.stddef;
import std.conv; import std.conv;
import std.traits; import std.traits;
import std.contracts; import std.contracts;
import std.file, std.typetuple; // for testing only import std.file;
import std.typetuple;
version (DigitalMars) version (DigitalMars)
{ {
@ -241,7 +242,7 @@ unittest
// test write // test write
string file = "dmd-build-test.deleteme.txt"; string file = "dmd-build-test.deleteme.txt";
FILE* f = fopen(file, "w"); FILE* f = fopen(file, "w");
assert(f); assert(f, getcwd());
write(f, "Hello, ", "world number ", 42, "!"); write(f, "Hello, ", "world number ", 42, "!");
fclose(f) == 0 || assert(false); fclose(f) == 0 || assert(false);
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!"); assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
@ -295,14 +296,19 @@ unittest
* equivalent to $(D_PARAM writef(stdout, args)). * equivalent to $(D_PARAM writef(stdout, args)).
* *
Warning: IMPORTANT:
New behavior starting with D 2.006: unlike previous versions, New behavior starting with D 2.006: unlike previous versions,
$(D_PARAM writef) (and also $(D_PARAM writefln)) only scans its first $(D_PARAM writef) (and also $(D_PARAM writefln)) only scans its first
string argument for format specifiers, but not subsequent string string argument for format specifiers, but not subsequent string
arguments. Also new in 2.006 is support for positional parameters arguments. This decision was made because the old behavior made it
with $(LINK2 http://www.opengroup.org/onlinepubs/009695399/functions/printf.html,POSIX) unduly hard to simply print string variables that occasionally
syntax. embedded percent signs.
Also new starting with 2.006 is support for positional
parameters with
$(LINK2 http://opengroup.org/onlinepubs/009695399/functions/printf.html,
POSIX) syntax.
Example: Example:
@ -313,11 +319,19 @@ writef("Date: %2$s %1$s", "October", 5); // "Date: 5 October"
The positional and non-positional styles can be mixed in the same The positional and non-positional styles can be mixed in the same
format string. (POSIX leaves this behavior undefined.) The internal format string. (POSIX leaves this behavior undefined.) The internal
counter for non-positional parameters tracks the next parameter after counter for non-positional parameters tracks the next parameter after
the largest positional parameter already used. */ the largest positional parameter already used.
New starting with 2.008: raw format specifiers. Using the "%r"
specifier makes $(D_PARAM writef) simply write the binary
representation of the argument. Use "%-r" to write numbers in little
endian format, "%+r" to write numbers in big endian format, and "%r"
to write numbers in platform-native format.
*/
void writef(T...)(T args) void writef(T...)(T args)
{ {
FileWriter!(char) w; PrivateFileWriter!(char) w;
static const errorMessage = static const errorMessage =
"You must pass a formatting string as the first" "You must pass a formatting string as the first"
" argument to writef. If no formatting is needed," " argument to writef. If no formatting is needed,"
@ -773,14 +787,14 @@ FILE* popen(string name, string mode)
/* /*
* Implements the static Writer interface for a FILE*. Instantiate it * Implements the static Writer interface for a FILE*. Instantiate it
* with the character type, e.g. FileWriter!(char), * with the character type, e.g. PrivateFileWriter!(char),
* FileWriter!(wchar), or FileWriter!(dchar). Regardless of * PrivateFileWriter!(wchar), or PrivateFileWriter!(dchar). Regardless of
* instantiation, FileWriter supports all character widths; it only is * instantiation, PrivateFileWriter supports all character widths; it only is
* the most efficient at accepting the character type it was * the most efficient at accepting the character type it was
* instantiated with. * instantiated with.
* *
* */ * */
private struct FileWriter(Char) private struct PrivateFileWriter(Char)
{ {
alias Char NativeChar; alias Char NativeChar;
FILE* backend; FILE* backend;
@ -929,10 +943,36 @@ Example:
struct lines struct lines
{ {
FILE * f; private FILE * f;
dchar terminator = '\n'; private dchar terminator = '\n';
private string fileName;
static lines opCall(FILE* f, dchar terminator = '\n')
{
lines result;
result.f = f;
result.terminator = terminator;
return result;
}
// Keep these commented lines for later, when Walter fixes the
// exception model.
// static lines opCall(string fName, dchar terminator = '\n')
// {
// auto f = enforce(fopen(fName),
// new StdioException("Cannot open file `"~fName~"' for reading"));
// auto result = lines(f, terminator);
// result.fileName = fName;
// return result;
// }
int opApply(D)(D dg) int opApply(D)(D dg)
{ {
// scope(exit) {
// if (fileName.length && fclose(f))
// StdioException("Could not close file `"~fileName~"'");
// }
alias ParameterTypeTuple!(dg) Parms; alias ParameterTypeTuple!(dg) Parms;
static if (isSomeString!(Parms[$ - 1])) static if (isSomeString!(Parms[$ - 1]))
{ {
@ -1151,8 +1191,32 @@ struct chunks
{ {
private FILE* f; private FILE* f;
private size_t size; private size_t size;
private string fileName;
static chunks opCall(FILE* f, size_t size)
{
assert(f && size);
chunks result;
result.f = f;
result.size = size;
return result;
}
// static chunks opCall(string fName, size_t size)
// {
// auto f = enforce(fopen(fName),
// new StdioException("Cannot open file `"~fName~"' for reading"));
// auto result = chunks(f, size);
// result.fileName = fName;
// return result;
// }
int opApply(int delegate(ref ubyte[]) dg) int opApply(int delegate(ref ubyte[]) dg)
{ {
// scope(exit) {
// if (fileName.length && fclose(f))
// StdioException("Could not close file `"~fileName~"'");
// }
const maxStackSize = 500 * 1024; const maxStackSize = 500 * 1024;
ubyte[] buffer = void; ubyte[] buffer = void;
if (size < maxStackSize) if (size < maxStackSize)

View file

@ -39,7 +39,10 @@ private import std.array;
private import std.format; private import std.format;
private import std.ctype; private import std.ctype;
private import std.stdarg; private import std.stdarg;
import std.contracts; private import std.contracts;
private import std.typetuple;
private import std.conv;
private import std.traits;
extern (C) extern (C)
{ {
@ -1539,6 +1542,194 @@ unittest
assert(i == 0); assert(i == 0);
} }
/**
* Returns $(D_PARAM true) if and only if the array $(D_PARAM longer)
* starts with array $(D_PARAM shorter).
*/
bool startsWith(A1, A2)(A1 longer, A2 shorter)
{
static if (is(typeof(longer[0 .. shorter.length] == shorter)))
{
// the easy way: arrays, directly comparable
return longer.length >= shorter.length &&
longer[0 .. shorter.length] == shorter;
}
else
{
// different element types, etc.
static if (isSomeString!(A1) && isSomeString!(A2))
{
// UTF-informed comparison
// find the largest character of the two
static if (longer[0].sizeof > shorter[0].sizeof)
{
alias typeof(longer[0]) Char;
if (shorter.length / Char.sizeof > longer.length) return false;
size_t i = 0;
foreach (Char c; shorter)
{
if (i == longer.length || longer[i] != c) return false;
++i;
}
}
else
{
static assert(longer[0].sizeof < shorter[0].sizeof,
"Looks like there's a bug in the compiler");
alias typeof(shorter[0]) Char;
if (shorter.length > longer.length) return false;
size_t i = 0;
foreach (Char c; longer)
{
if (i == shorter.length) return true;
if (shorter[i] != c) return false;
++i;
}
}
}
else
{
// raw element-by-element comparison
if (longer.length < shorter.length) return false;
foreach (i, e; shorter)
{
if (longer[i] != e) return false;
}
}
}
return true;
}
unittest
{
alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[])
StringTypes;
alias TypeTuple!(ubyte[], int[], double[]) OtherTypes;
foreach (T1 ; StringTypes)
{
foreach (T2 ; StringTypes)
{
foreach (T3 ; OtherTypes)
{
auto a = to!(T1)("abcde"), b = to!(T2)("abcdefgh"),
c = to!(T2)("");
auto d = to!(T3)([2, 3]);
assert(startsWith(b, a));
assert(!startsWith(a, b));
assert(startsWith(b, c));
assert(startsWith(a, c));
assert(!startsWith(c, b));
assert(!startsWith(c, a));
assert(!startsWith(a, d));
assert(!startsWith(d, a));
assert(!startsWith(b, d));
assert(!startsWith(d, b));
assert(!startsWith(c, d));
assert(startsWith(d, c));
}
}
}
}
/**
* Returns $(D_PARAM true) if and only if the array $(D_PARAM longer)
* ends with array $(D_PARAM shorter).
*/
bool endsWith(A1, A2)(A1 longer, A2 shorter)
{
static if (is(typeof(longer[$ - shorter.length .. $] == shorter)))
{
// the easy way: arrays, directly comparable
return longer.length >= shorter.length &&
longer[$ - shorter.length .. $] == shorter;
}
else
{
// different element types, etc.
static if (isSomeString!(A1) && isSomeString!(A2))
{
// UTF-informed comparison
// find the largest character of the two
static if (longer[0].sizeof > shorter[0].sizeof)
{
alias typeof(longer[0]) Char;
if (shorter.length > longer.length * Char.sizeof) return false;
size_t i = longer.length - 1;
foreach_reverse (Char c; shorter)
{
if (i == 0 || longer[i] != c) return false;
--i;
}
}
else
{
static assert(longer[0].sizeof < shorter[0].sizeof,
"Looks like there's a bug in the compiler");
alias typeof(shorter[0]) Char;
if (shorter.length > longer.length) return false;
if (!shorter.length) return true;
size_t i = shorter.length - 1;
foreach_reverse (Char c; longer)
{
if (i == 0) return true;
if (shorter[i] != c) return false;
--i;
}
}
}
else
{
// raw element-by-element comparison
if (longer.length < shorter.length) return false;
foreach (i, e; longer[$ - shorter.length .. $])
{
if (shorter[i] != e) return false;
}
}
}
return true;
}
unittest
{
alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[])
TestTypes;
alias TypeTuple!(ubyte[], int[], double[]) OtherTypes;
foreach (T1 ; TestTypes)
{
foreach (T2 ; TestTypes)
{
foreach (T3 ; OtherTypes)
{
auto a = to!(T1)("efgh"), b = to!(T2)("abcdefgh"),
c = to!(T2)(""), d = to!(T3)([1, 2]);
assert(endsWith(b, a));
assert(!endsWith(a, b));
assert(endsWith(b, c));
assert(endsWith(a, c));
assert(!endsWith(c, b));
assert(!endsWith(c, a));
assert(!endsWith(a, d));
assert(!endsWith(d, a));
assert(!endsWith(b, d));
assert(!endsWith(d, b));
assert(!endsWith(c, d));
assert(endsWith(d, c));
}
}
}
foreach (T1; OtherTypes)
{
foreach (T2; OtherTypes)
{
auto a = to!(T1)([1, 2]);
auto b = to!(T2)([0, 1, 2]);
assert(!endsWith(a, b));
assert(endsWith(b, a));
}
}
}
/******************************************* /*******************************************
* Returns s[] sans trailing delimiter[], if any. * Returns s[] sans trailing delimiter[], if any.
* If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any.
@ -1608,6 +1799,23 @@ unittest
assert(s == "he"); assert(s == "he");
} }
/**
* If $(D_PARAM longer.startsWith(shorter)), returns $(D_PARAM
* longer[shorter.length .. $]). Otherwise, returns $(D_PARAM longer).
*/
C1[] chompPrefix(C1, C2)(C1[] longer, C2[] shorter)
{
return startsWith(longer, shorter) ? longer[shorter.length .. $]
: longer;
}
unittest
{
auto a = "abcde", b = "abcdefgh";
assert(chompPrefix(b, a) == "fgh");
assert(chompPrefix(a, b) == "abcde");
}
/*********************************************** /***********************************************
* Returns s[] sans trailing character, if there is one. * Returns s[] sans trailing character, if there is one.
@ -3018,7 +3226,7 @@ certain category of characters (e.g. whitespace) when parsing
strings. (In such cases, the return value is not used.) strings. (In such cases, the return value is not used.)
*/ */
S munch(S)(ref S s, S pattern) S1 munch(S1, S2)(ref S1 s, S2 pattern)
{ {
size_t j = s.length; size_t j = s.length;
foreach (i, c; s) foreach (i, c; s)

View file

@ -271,6 +271,41 @@ unittest
assert(TransitiveBaseTypeTuple!(Object).length == 0); assert(TransitiveBaseTypeTuple!(Object).length == 0);
} }
/**
Get the type that all types can be implicitly converted to. Useful
e.g. in figuring out an array type from a bunch of initializing
values. Returns $(D_PARAM void) if passed an empty list, or if the
types have no common type.
Example:
----
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(int, char[], short) Y;
assert(is(Y == void));
----
*/
template CommonType(T...)
{
static if (!T.length)
alias void CommonType;
else static if (T.length == 1)
alias T[0] CommonType;
else static if (is(typeof(true ? T[0] : T[1]) U))
alias CommonType!(U, T[2 .. $]) CommonType;
else
alias void CommonType;
}
unittest
{
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(char[], int, long, short) Y;
assert(is(Y == void), Y.stringof);
}
/** /**
* Returns a tuple with all possible target types of an implicit * Returns a tuple with all possible target types of an implicit
* conversion of a value of type $(D_PARAM T). * conversion of a value of type $(D_PARAM T).
@ -322,9 +357,6 @@ template ImplicitConversionTargets(T)
else static if (is(T == double)) else static if (is(T == double))
alias TypeTuple!(real) alias TypeTuple!(real)
ImplicitConversionTargets; ImplicitConversionTargets;
// else static if (is(T == real))
// alias TypeTuple!()
// ImplicitConversionTargets;
else static if (is(T == char)) else static if (is(T == char))
alias TypeTuple!(wchar, dchar, byte, ubyte, short, ushort, alias TypeTuple!(wchar, dchar, byte, ubyte, short, ushort,
int, uint, long, ulong, float, double, real) int, uint, long, ulong, float, double, real)
@ -356,33 +388,36 @@ unittest
template isIntegral(T) template isIntegral(T)
{ {
static const isIntegral = is(T == byte) || is(T == ubyte) || is(T == short) static const isIntegral = is(T == byte) || is(T == ubyte) || is(T == short)
|| is(T == ushort) || is(T == int) || is(T == uint) || is(T == ushort) || is(T == int) || is(T == uint)
|| is(T == long) || is(T == ulong); || is(T == long) || is(T == ulong);
} }
/** /**
* Detect whether T is a built-in floating point type * Detect whether T is a built-in floating point type
*/ */
template isFloatingPoint(T) { template isFloatingPoint(T)
static const isFloatingPoint = is(T == float) {
|| is(T == double) || is(T == real); static const isFloatingPoint = is(T == float)
|| is(T == double) || is(T == real);
} }
/** /**
* Detect whether T is a built-in numeric type * Detect whether T is a built-in numeric type
*/ */
template isNumeric(T) { template isNumeric(T)
static const isNumeric = isIntegral!(T) || isFloatingPoint!(T); {
static const isNumeric = isIntegral!(T) || isFloatingPoint!(T);
} }
/** /**
* Detect whether T is one of the built-in string types * Detect whether T is one of the built-in string types
*/ */
template isSomeString(T) { template isSomeString(T)
{
static const isSomeString = is(T : const(char[])) static const isSomeString = is(T : const(char[]))
|| is(T : const(wchar[])) || is(T : const(dchar[])); || is(T : const(wchar[])) || is(T : const(dchar[]));
} }
@ -403,9 +438,8 @@ static assert(isSomeString!(char[4]));
template isAssociativeArray(T) template isAssociativeArray(T)
{ {
static const bool isAssociativeArray static const bool isAssociativeArray =
= is(typeof(T.keys)) && is(typeof(T.values)); is(typeof(T.keys)) && is(typeof(T.values));
// = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T);
} }
static assert(!isAssociativeArray!(int)); static assert(!isAssociativeArray!(int));
@ -414,19 +448,25 @@ static assert(isAssociativeArray!(int[int]));
static assert(isAssociativeArray!(int[string])); static assert(isAssociativeArray!(int[string]));
static assert(isAssociativeArray!(invariant(char[5])[int])); static assert(isAssociativeArray!(invariant(char[5])[int]));
/**
* Detect whether type T is a static array.
*/
template isStaticArray(T : U[N], U, size_t N)
{
const bool isStaticArray = true;
}
template isStaticArray(T) template isStaticArray(T)
{ {
const bool isStaticArray = false; const bool isStaticArray = false;
} }
template isStaticArray(T : T[N], size_t N)
{
const bool isStaticArray = true;
}
static assert (isStaticArray!(int[51])); static assert (isStaticArray!(int[51]));
static assert (isStaticArray!(int[][2])); static assert (isStaticArray!(int[][2]));
static assert (isStaticArray!(char[][int][11])); static assert (isStaticArray!(char[][int][11]));
static assert (!isStaticArray!(const(int)[]));
static assert (!isStaticArray!(invariant(int)[]));
static assert (!isStaticArray!(const(int)[4][]));
static assert (!isStaticArray!(int[])); static assert (!isStaticArray!(int[]));
static assert (!isStaticArray!(int[char])); static assert (!isStaticArray!(int[char]));
static assert (!isStaticArray!(int[1][])); static assert (!isStaticArray!(int[1][]));
@ -434,6 +474,9 @@ static assert(isStaticArray!(invariant char[13u]));
static assert(isStaticArray!(void[0])); static assert(isStaticArray!(void[0]));
static assert(!isStaticArray!(int[int])); static assert(!isStaticArray!(int[int]));
static assert(!isStaticArray!(int)); static assert(!isStaticArray!(int));
static assert(isStaticArray!(const(real)[1]));
static assert(isStaticArray!(const(real)[1][1]));
static assert(isStaticArray!(typeof("string literal")));
/** /**
* Detect whether type T is a dynamic array. * Detect whether type T is a dynamic array.

299
std/typecons.d Normal file
View file

@ -0,0 +1,299 @@
// Written in the D programming language.
/**
This module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.
Macros:
WIKI = Phobos/StdVariant
Synopsis:
----
// value tuples
alias Tuple!(float, "x", float, "y", float, "z") Coord;
Coord c;
c._0 = 1; // access by index-based name
c.field!(1) = 1; // access by index
c.z = 1; // access by given name
alias Tuple!(string, string) DicEntry; // names can be omitted
// enumerated values with conversions to and from strings
mixin(defineEnum!("Openmode", "READ", "WRITE", "READWRITE", "APPEND"));
void foo()
{
Openmode m = Openmode.READ;
string s = toString(m);
assert(s == "READ");
Openmode m1;
assert(fromString(s, m1) && m1 == m);
}
----
Author:
Andrei Alexandrescu
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Andrei Alexandrescu, www.erdani.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module std.typecons;
//private import std.stdio;
private import std.metastrings;
private import std.contracts;
private import std.typetuple;
private string tupleImpl(uint index, T...)()
{
static if (!T.length)
{
return "";
}
else
{
auto indexStr = ToString!(index);
string decl = T[0].stringof~" _"~indexStr~";"
~"\ntemplate field(int i : "~indexStr~") { alias _"~indexStr
~" field; }\n";
static if (is(typeof(T[1]) : string))
{
//return T[0].stringof ~ " " ~ T[1] ~ ";" ~ tupleImpl!(T[2 .. $])();
decl ~= "alias _" ~ ToString!(index) ~ " " ~ T[1] ~ ";\n";
return decl ~ tupleImpl!(index + 1, T[2 .. $]);
}
else
{
return decl ~ tupleImpl!(index + 1, T[1 .. $]);
}
}
}
/**
Tuple of values, for example $(D_PARAM Tuple!(int, string)) is a
record that stores an $(D_PARAM int) and a $(D_PARAM
string). $(D_PARAM Tuple) can be used to bundle values together,
notably when returning multiple values from a function. If $(D_PARAM
obj) is a tuple, the individual members are accessible with the syntax
$(D_PARAM obj.field!(0)) for the first field, $(D_PARAM obj.field!(1))
for the second, and so on. A shortcut notation is $(D_PARAM
obj.)&#95;$(D_PARAM 0), $(D_PARAM obj.)&#95;$(D_PARAM 1) etc.
The choice of zero-based indexing instead of one-base indexing was
motivated by the ability to use value tuples with various compile-time
loop constructs (e.g. type tuple iteration), all of which use
zero-based indexing.
Example:
----
Tuple!(int, int) point;
// assign coordinates
point._0 = 5;
point.field!(1) = 6;
// read coordinates
auto x = point.field!(0);
auto y = point._1;
----
Tuple members can be named. It is legal to mix named and unnamed
members. The method above is still applicable to all fields.
Example:
----
alias Tuple!(int, "index", string, "value") Entry;
Entry e;
e.index = 4;
e.value = "Hello";
assert(e._1 == "Hello");
assert(e.field!(0) == 4);
----
Tuples with named fields are distinct types from tuples with unnamed
fields, i.e. each naming imparts a separate type for the tuple. Two
tuple differing in naming only are still distinct, even though they
might have the same structure.
Example:
----
Tuple!(int, "x", int, "y") point1;
Tuple!(int, int) point2;
assert(!is(typeof(point1) == typeof(point2))); // passes
----
*/
struct Tuple(T...)
{
mixin(tupleImpl!(0, T));
}
unittest
{
Tuple!(int, "a", int, "b") nosh;
nosh.a = 5;
assert(nosh._0 == 5);
assert(nosh.field!(0) == 5);
Tuple!(int, int, "b") nosh1;
assert(!is(typeof(nosh) == typeof(nosh1)));
}
private string enumValuesImpl(string name, BaseType, long index, T...)()
{
static if (name.length)
{
return "enum "~name~" : "~BaseType.stringof
~" { "~enumValuesImpl!("", BaseType, index, T)()~"}\n";
}
else
{
static if (!T.length) return "";
else
{
static if (T.length == 1 || is(typeof(T[1]) : string))
{
return T[0]~" = "~ToString!(index)~", "
~enumValuesImpl!("", BaseType, index + 1, T[1 .. $])();
}
else
{
return T[0]~" = "~ToString!(T[1])~", "
~enumValuesImpl!("", BaseType, T[1] + 1, T[2 .. $])();
}
}
}
}
private string enumParserImpl(string name, bool first, T...)()
{
static if (first)
{
return "bool fromString(string s, ref "~name~" v) {\n"
~enumParserImpl!(name, false, T)
~"return false;\n}\n";
}
else
{
static if (T.length)
return "if (s == `"~T[0]~"`) return (v = "~name~"."~T[0]~"), true;\n"
~enumParserImpl!(name, false, T[1 .. $]);
else
return "";
}
}
private string enumPrinterImpl(string name, bool first, T...)()
{
static if (first)
{
return "string toString("~name~" v) {\n"
~enumPrinterImpl!(name, false, T)~"}\n";
}
else
{
static if (T.length)
return "if (v == "~name~"."~T[0]~") return `"~T[0]~"`;\n"
~enumPrinterImpl!(name, false, T[1 .. $]);
else
return "";
}
}
private template ValueTuple(T...)
{
alias T ValueTuple;
}
private template StringsOnly(T...)
{
static if (T.length == 1)
static if (is(typeof(T[0]) : string))
alias ValueTuple!(T[0]) StringsOnly;
else
alias ValueType!() StringsOnly;
else
static if (is(typeof(T[0]) : string))
alias ValueTuple!(T[0], StringsOnly!(T[1 .. $])) StringsOnly;
else
alias ValueTuple!(StringsOnly!(T[1 .. $])) StringsOnly;
}
/**
Defines truly named enumerated values with parsing and stringizing
primitives.
Example:
----
mixin(defineEnum!("Abc", "A", "B", 5, "C"));
----
is equivalent to the following code:
----
enum Abc { A, B = 5, C }
string toString(Abc v) { ... }
Abc fromString(string s) { ... }
----
The $(D_PARAM toString) function generates the unqualified names of the
enumerated values, i.e. "A", "B", and "C". The $(D_PARAM fromString)
function expects one of "A", "B", and "C", and throws an exception in
any other case.
A base type can be specified for the enumeration like this:
----
mixin(defineEnum!("Abc", ubyte, "A", "B", "C", 255));
----
In this case the generated $(D_PARAM enum) will have a $(D_PARAM
ubyte) representation.
*/
template defineEnum(string name, T...)
{
static if (is(typeof(cast(T[0]) T[0].init)))
static const string defineEnum =
enumValuesImpl!(name, T[0], 0, T[1 .. $])()
~ enumParserImpl!(name, true, StringsOnly!(T[1 .. $]))()
~ enumPrinterImpl!(name, true, StringsOnly!(T[1 .. $]))();
else
alias defineEnum!(name, int, T) defineEnum;
}
private
{
mixin(defineEnum!("Abc", "A", 1, "B", "C"));
mixin(defineEnum!("Def", byte, "D", 1, "E", "F"));
}
unittest
{
Abc a = Abc.A;
assert(toString(a) == "A");
Abc b;
assert(fromString("B", b) && b == Abc.B);
}

View file

@ -577,6 +577,11 @@ public:
{ {
return to!(T)(toString); return to!(T)(toString);
} }
else
{
// Fix for bug 1649
static assert(false);
}
} }
/** /**
@ -919,6 +924,28 @@ alias VariantN!(maxSize!(creal, char[], void delegate())) Variant;
* auto b = Variant(a); // variant array as variant * auto b = Variant(a); // variant array as variant
* assert(b[1] == 3.14); * assert(b[1] == 3.14);
* ---- * ----
*
* Code that needs functionality similar to the $(D_PARAM boxArray)
* function in the $(D_PARAM std.boxer) module can achieve it like this:
*
* ----
* // old
* Box[] fun(...)
* {
* ...
* return boxArray(_arguments, _argptr);
* }
* // new
* Variant[] fun(T...)(T args)
* {
* ...
* return variantArray(args);
* }
* ----
*
* This is by design. During construction the $(D_PARAM Variant) needs
* static type information about the type being held, so as to store a
* pointer to function for fast retrieval.
*/ */
Variant[] variantArray(T...)(T args) Variant[] variantArray(T...)(T args)