mirror of
https://github.com/dlang/phobos.git
synced 2025-05-02 08:00:48 +03:00
Initial merge of candidate to trunk for r459:513
This commit is contained in:
parent
0e9836f3cb
commit
09916d399a
24 changed files with 3629 additions and 1110 deletions
15
linux.mak
15
linux.mak
|
@ -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
|
||||||
|
|
4
std.ddoc
4
std.ddoc
|
@ -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
439
std/algorithm.d
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
937
std/bitarray.d
937
std/bitarray.d
|
@ -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 & ~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 &= ~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
1187
std/bitmanip.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||||
|
|
|
@ -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)).
|
||||||
|
|
59
std/conv.d
59
std/conv.d
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
15
std/file.d
15
std/file.d
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
130
std/format.d
130
std/format.d
|
@ -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
49
std/functional.d
Normal 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; }
|
85
std/math.d
85
std/math.d
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
@ -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
85
std/numeric.d
Normal 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));
|
||||||
|
}
|
||||||
|
|
71
std/path.d
71
std/path.d
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ////////////////////////////////////////////////////////////////////////// */
|
/* ////////////////////////////////////////////////////////////////////////// */
|
||||||
|
|
||||||
|
|
662
std/random.d
662
std/random.d
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
203
std/regexp.d
203
std/regexp.d
|
@ -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");
|
||||||
|
|
98
std/stdio.d
98
std/stdio.d
|
@ -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)
|
||||||
|
|
212
std/string.d
212
std/string.d
|
@ -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)
|
||||||
|
|
83
std/traits.d
83
std/traits.d
|
@ -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
299
std/typecons.d
Normal 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.)_$(D_PARAM 0), $(D_PARAM obj.)_$(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);
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue