mirror of
https://github.com/dlang/phobos.git
synced 2025-05-06 11:07:39 +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/linux.mak
|
||||
|
||||
STD_MODULES = array asserterror base64 bind bitarray boxer compiler contracts \
|
||||
conv cover cpuid cstream ctype date dateparse demangle file format gc \
|
||||
getopt hiddenfunc intrinsic loader math math2 md5 metastrings mmfile \
|
||||
moduleinit openrj outbuffer outofmemory path perf process random \
|
||||
regexp signals slist socket socketstream stdint stdio stream string \
|
||||
switcherr syserror system thread traits typetuple uni uri utf variant \
|
||||
zip zlib
|
||||
STD_MODULES = algorithm array asserterror base64 bind bitarray \
|
||||
bitmanip boxer compiler contracts conv cover cpuid cstream \
|
||||
ctype date dateparse demangle file format functional gc getopt \
|
||||
hiddenfunc intrinsic loader math math2 md5 metastrings mmfile \
|
||||
moduleinit numeric openrj outbuffer outofmemory path perf \
|
||||
process random regexp signals socket socketstream stdint stdio \
|
||||
stream string switcherr syserror system thread traits typecons \
|
||||
typetuple uni uri utf variant zip zlib
|
||||
STD_MODULES_NOTBUILT = stdarg
|
||||
|
||||
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>
|
||||
$(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_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_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_compiler.html" title="Information about the D compiler implementation">std.compiler</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_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_numeric.html" title="Numeric algorithms">std.numeric</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_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_thread.html" title="Thread operations">std.thread</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_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>)
|
||||
|
|
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
|
||||
|
||||
/***********************
|
||||
* Scheduled for deprecation. Use $(LINK2
|
||||
* std_bitmanip.html,std.bitmanip) instead.
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = StdBitarray
|
||||
*/
|
||||
|
||||
module std.bitarray;
|
||||
public import std.bitmanip;
|
||||
|
||||
//debug = bitarray; // uncomment to turn on debugging printf's
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
pragma(msg, "You may want to import std.bitmanip instead of std.bitarray");
|
||||
|
|
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 BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime);
|
||||
export HANDLE GetCurrentProcess();
|
||||
export DWORD GetCurrentProcessId();
|
||||
export BOOL DuplicateHandle (HANDLE sourceProcess, HANDLE sourceThread,
|
||||
HANDLE targetProcessHandle, HANDLE *targetHandle, DWORD access,
|
||||
BOOL inheritHandle, DWORD options);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* ----
|
||||
*
|
||||
* Author:
|
||||
*
|
||||
* Andrei Alexandrescu
|
||||
*
|
||||
* Credits:
|
||||
|
@ -36,6 +37,7 @@
|
|||
*/
|
||||
|
||||
module std.contracts;
|
||||
private import std.conv;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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
|
||||
* $(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)
|
||||
{
|
||||
scope(exit) { if (v.length) conv_error(v.idup); }
|
||||
scope(exit)
|
||||
{
|
||||
if (v.length)
|
||||
{
|
||||
conv_error!(const(char)[], T)(v);
|
||||
}
|
||||
}
|
||||
return parse!(T)(v);
|
||||
}
|
||||
|
||||
|
@ -667,7 +675,10 @@ private N parseIntegral(S, N)(ref S s)
|
|||
alias uint N1;
|
||||
auto v = parseIntegral!(S, N1)(s);
|
||||
auto result = cast(N) v;
|
||||
if (result != v) conv_error(to!(string)(s));
|
||||
if (result != v)
|
||||
{
|
||||
conv_error!(S, N)(s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
|
@ -724,7 +735,7 @@ private N parseIntegral(S, N)(ref S s)
|
|||
Loverflow:
|
||||
conv_overflow(to!(string)(s));
|
||||
Lerr:
|
||||
conv_error(to!(string)(s));
|
||||
conv_error!(S, N)(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -736,7 +747,7 @@ private N parseIntegral(S, N)(ref S 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);
|
||||
}
|
||||
|
||||
|
@ -811,7 +822,7 @@ unittest
|
|||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -880,7 +891,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -961,7 +972,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1037,7 +1048,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1123,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1182,7 +1193,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1257,7 +1268,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1327,7 +1338,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1341,6 +1352,12 @@ F parseFloating(S : S[], F)(ref S[] s)
|
|||
if (std.ctype.isspace(*sz))
|
||||
goto Lerr;
|
||||
|
||||
// issue 1589
|
||||
version (Windows)
|
||||
{
|
||||
if (icmp(s, "nan") == 0) return F.nan;
|
||||
}
|
||||
|
||||
// BUG: should set __locale_decpoint to "." for DMC
|
||||
|
||||
setErrno(0);
|
||||
|
@ -1364,7 +1381,7 @@ F parseFloating(S : S[], F)(ref S[] s)
|
|||
s = s[endptr - sz .. $];
|
||||
return f;
|
||||
Lerr:
|
||||
conv_error(to!(string)(s) ~ " not representable as a " ~ F.stringof);
|
||||
conv_error!(S[], F)(s);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
@ -1373,6 +1390,8 @@ unittest
|
|||
debug( conv ) writefln( "conv.toFloat.unittest" );
|
||||
float f;
|
||||
|
||||
f = toFloat( "nAn" );
|
||||
assert(isnan(f));
|
||||
f = toFloat( "123" );
|
||||
assert( f == 123f );
|
||||
f = toFloat( "+123" );
|
||||
|
@ -1418,7 +1437,7 @@ unittest
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1474,7 +1493,7 @@ unittest
|
|||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1907,9 +1926,7 @@ unittest
|
|||
* Grammar:
|
||||
* ['+'|'-'] string floating-point digit {digit}
|
||||
*/
|
||||
// @@@ BUG IN COMPILER: writing "in string s" instead of "string s" changes its
|
||||
// type from invariant(char)[] to const(char)[] !!!
|
||||
private bool getComplexStrings(string s, out string s1, out string s2)
|
||||
private bool getComplexStrings(in string s, out string s1, out string s2)
|
||||
{
|
||||
int len = s.length;
|
||||
|
||||
|
@ -1953,7 +1970,7 @@ private bool getComplexStrings(string s, out string s1, out string s2)
|
|||
|
||||
Lerr:
|
||||
// Display the original string in the error message.
|
||||
conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\""
|
||||
throw new ConvError("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\""
|
||||
~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\"");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ module std.cover;
|
|||
|
||||
private import std.stdio;
|
||||
private import std.file;
|
||||
private import std.bitarray;
|
||||
private import std.bitmanip;
|
||||
|
||||
private
|
||||
{
|
||||
|
|
15
std/file.d
15
std/file.d
|
@ -1591,6 +1591,8 @@ struct DirIterator
|
|||
int opApply(D)(D dg)
|
||||
{
|
||||
int result = 0;
|
||||
string[] worklist = [ pathname ]; // used only in breadth-first traversal
|
||||
|
||||
bool callback(DirEntry* de)
|
||||
{
|
||||
switch (mode)
|
||||
|
@ -1602,7 +1604,7 @@ struct DirIterator
|
|||
result = doIt(dg, de);
|
||||
if (!result && de.isdir)
|
||||
{
|
||||
listdir(de.name, &callback);
|
||||
worklist ~= de.name;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1618,8 +1620,15 @@ struct DirIterator
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
130
std/format.d
130
std/format.d
|
@ -47,6 +47,8 @@ import std.conv;
|
|||
import std.traits;
|
||||
import std.typetuple;
|
||||
import std.stdio; // for debugging only
|
||||
import std.contracts;
|
||||
import std.system;
|
||||
|
||||
version (Windows)
|
||||
{
|
||||
|
@ -77,8 +79,6 @@ else
|
|||
*/
|
||||
class FormatError : Error
|
||||
{
|
||||
private:
|
||||
|
||||
this()
|
||||
{
|
||||
super("std.format");
|
||||
|
@ -1773,6 +1773,24 @@ unittest
|
|||
*/
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if (std.string.find("fgFGaAeEs", f.spec) < 0) {
|
||||
throw new FormatError("floating");
|
||||
}
|
||||
if (f.spec == 's') f.spec = 'g';
|
||||
char sprintfSpec[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/
|
||||
+ 1 /*\0*/] = void;
|
||||
sprintfSpec[0] = '%';
|
||||
uint i = 1;
|
||||
if (f.flDash) sprintfSpec[i++] = '-';
|
||||
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)]);
|
||||
if (f.spec == 'r')
|
||||
{
|
||||
// raw write, skip all else and write the thing
|
||||
auto begin = cast(const char*) &obj;
|
||||
if (std.system.endian == Endian.LittleEndian && f.flPlus
|
||||
|| std.system.endian == Endian.BigEndian && f.flDash)
|
||||
{
|
||||
// must swap bytes
|
||||
foreach_reverse (i; 0 .. obj.sizeof)
|
||||
w.putchar(begin[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (i; 0 .. obj.sizeof)
|
||||
w.putchar(begin[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (std.string.find("fgFGaAeEs", f.spec) < 0) {
|
||||
throw new FormatError("floating");
|
||||
}
|
||||
if (f.spec == 's') f.spec = 'g';
|
||||
char sprintfSpec[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/
|
||||
+ 1 /*\0*/] = void;
|
||||
sprintfSpec[0] = '%';
|
||||
uint i = 1;
|
||||
if (f.flDash) sprintfSpec[i++] = '-';
|
||||
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)
|
||||
{
|
||||
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 to!(int)(arg);
|
||||
return getNthInt(index - 1, args[1 .. $]);
|
||||
}
|
||||
static if (is(typeof(args[0]) : long) || is(typeof(arg) : ulong))
|
||||
{
|
||||
return to!(int)(args[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i == index) break;
|
||||
throw new FormatError("int expected");
|
||||
}
|
||||
}
|
||||
throw new FormatError("int expected");
|
||||
else
|
||||
{
|
||||
throw new FormatError("int expected");
|
||||
}
|
||||
}
|
||||
|
||||
/* (Not public yet.)
|
||||
|
@ -2146,6 +2189,21 @@ void formattedWrite(Writer, F, A...)(ref Writer w, const(F)[] fmt, A args)
|
|||
|
||||
/* ======================== 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
|
||||
{
|
||||
// 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.string;
|
||||
private import std.c.math;
|
||||
private import std.traits;
|
||||
|
||||
class NotImplemented : Error
|
||||
{
|
||||
|
@ -1429,10 +1430,32 @@ real nan(char[] tagp) { return std.c.math.nanl(toStringz(tagp)); }
|
|||
*/
|
||||
real nextafter(real x, real y)
|
||||
{
|
||||
version (linux)
|
||||
return std.c.math.nextafterl(x, y);
|
||||
else
|
||||
throw new NotImplemented("nextafter");
|
||||
return std.c.math.nextafterl(x, y);
|
||||
}
|
||||
|
||||
/// 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); }
|
||||
|
@ -1887,4 +1910,58 @@ unittest
|
|||
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)
|
||||
{
|
||||
static if (U < 10)
|
||||
const char[] ToString = "" ~ cast(char)(U + '0');
|
||||
invariant char[] ToString = "" ~ cast(char)(U + '0');
|
||||
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
|
||||
template ToString(long I)
|
||||
{
|
||||
static if (I < 0)
|
||||
const char[] ToString = "-" ~ ToString!(cast(ulong)(-I));
|
||||
invariant char[] ToString = "-" ~ ToString!(cast(ulong)(-I));
|
||||
else
|
||||
const char[] ToString = ToString!(cast(ulong)I);
|
||||
invariant char[] ToString = ToString!(cast(ulong)I);
|
||||
}
|
||||
|
||||
static assert(ToString!(0x100000000) == "4294967296");
|
||||
|
@ -93,55 +95,55 @@ static assert(ToString!(0x100000000) == "4294967296");
|
|||
/// ditto
|
||||
template ToString(uint U)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(ulong)U);
|
||||
invariant char[] ToString = ToString!(cast(ulong)U);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(int I)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(long)I);
|
||||
invariant char[] ToString = ToString!(cast(long)I);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(ushort U)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(ulong)U);
|
||||
invariant char[] ToString = ToString!(cast(ulong)U);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(short I)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(long)I);
|
||||
invariant char[] ToString = ToString!(cast(long)I);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(ubyte U)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(ulong)U);
|
||||
invariant char[] ToString = ToString!(cast(ulong)U);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(byte I)
|
||||
{
|
||||
const char[] ToString = ToString!(cast(long)I);
|
||||
invariant char[] ToString = ToString!(cast(long)I);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(bool B)
|
||||
{
|
||||
const char[] ToString = B ? "true" : "false";
|
||||
invariant char[] ToString = B ? "true" : "false";
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(string S)
|
||||
{
|
||||
const char[] ToString = S;
|
||||
invariant char[] ToString = S;
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template ToString(char C)
|
||||
{
|
||||
const char[] ToString = "" ~ C;
|
||||
invariant char[] ToString = "" ~ C;
|
||||
}
|
||||
|
||||
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.string;
|
||||
private import std.file;
|
||||
|
||||
version(linux)
|
||||
{
|
||||
|
@ -36,35 +37,35 @@ version(Windows)
|
|||
|
||||
/** String used to separate directory names in a path. Under
|
||||
* 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
|
||||
* Linux this is empty. */
|
||||
const char[1] altsep = "/";
|
||||
invariant char[1] altsep = "/";
|
||||
/** Path separator string. A semi colon under Windows, a colon
|
||||
* under Linux. */
|
||||
const char[1] pathsep = ";";
|
||||
invariant char[1] pathsep = ";";
|
||||
/** String used to separate lines, \r\n under Windows and \n
|
||||
* under Linux. */
|
||||
const char[2] linesep = "\r\n"; /// String used to separate lines.
|
||||
const char[1] curdir = "."; /// String representing the current directory.
|
||||
const char[2] pardir = ".."; /// String representing the parent directory.
|
||||
invariant char[2] linesep = "\r\n"; /// String used to separate lines.
|
||||
invariant char[1] curdir = "."; /// String representing the current directory.
|
||||
invariant char[2] pardir = ".."; /// String representing the parent directory.
|
||||
}
|
||||
version(linux)
|
||||
{
|
||||
/** String used to separate directory names in a path. Under
|
||||
* 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
|
||||
* Linux this is empty. */
|
||||
const char[0] altsep;
|
||||
invariant char[0] altsep;
|
||||
/** Path separator string. A semi colon under Windows, a colon
|
||||
* under Linux. */
|
||||
const char[1] pathsep = ":";
|
||||
invariant char[1] pathsep = ":";
|
||||
/** String used to separate lines, \r\n under Windows and \n
|
||||
* under Linux. */
|
||||
const char[1] linesep = "\n";
|
||||
const char[1] curdir = "."; /// String representing the current directory.
|
||||
const char[2] pardir = ".."; /// String representing the parent directory.
|
||||
invariant char[1] linesep = "\n";
|
||||
invariant char[1] curdir = "."; /// String representing the current 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.
|
||||
*
|
||||
|
|
|
@ -37,6 +37,10 @@ private import std.c.stdlib;
|
|||
private import std.c.string;
|
||||
private import std.string;
|
||||
private import std.c.process;
|
||||
version (Windows)
|
||||
{
|
||||
private import std.c.windows.windows:GetCurrentProcessId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command in a _command shell.
|
||||
|
@ -247,6 +251,15 @@ else
|
|||
} // version
|
||||
}
|
||||
|
||||
version(linux)
|
||||
{
|
||||
alias std.c.process.getpid getpid;
|
||||
}
|
||||
else version (Windows)
|
||||
{
|
||||
alias std.c.windows.windows.GetCurrentProcessId getpid;
|
||||
}
|
||||
|
||||
/* ////////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdRandom
|
||||
*/
|
||||
Facilities for random number generation. The old-style functions
|
||||
$(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
|
||||
// www.digitalmars.com
|
||||
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
extern(Windows) int QueryPerformanceCounter(ulong *count);
|
||||
|
@ -23,6 +118,557 @@ version (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 ========================= */
|
||||
|
||||
// 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.
|
||||
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)
|
||||
{
|
||||
|
@ -51,7 +700,8 @@ void rand_seed(uint seed, uint index)
|
|||
|
||||
/**
|
||||
* 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()
|
||||
|
@ -109,7 +759,7 @@ static this()
|
|||
|
||||
if (gettimeofday(&tv, null))
|
||||
{ // Some error happened - try time() instead
|
||||
s = time(null);
|
||||
s = std.c.linux.linux.time(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
203
std/regexp.d
203
std/regexp.d
|
@ -143,7 +143,7 @@ private
|
|||
import std.string;
|
||||
import std.ctype;
|
||||
import std.outbuffer;
|
||||
import std.bitarray;
|
||||
import std.bitmanip;
|
||||
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://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}";
|
||||
|
||||
/** 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
|
||||
|
@ -237,7 +237,7 @@ unittest
|
|||
* sub(s, "[ar]",
|
||||
* delegate char[] (RegExp m)
|
||||
* {
|
||||
* return toupper(m.match(0));
|
||||
* return toupper(m[0]);
|
||||
* },
|
||||
* "g"); // result: StRAp A Rocket engine on A chicken.
|
||||
* ---
|
||||
|
@ -308,7 +308,7 @@ unittest
|
|||
"[ar]",
|
||||
delegate string (RegExp m)
|
||||
{
|
||||
return std.string.toupper(m.match(0));
|
||||
return std.string.toupper(m[0]);
|
||||
},
|
||||
"g");
|
||||
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:
|
||||
* s = String to search.
|
||||
* pattern = Regular expression pattern.
|
||||
* attributes = Regular expression attributes.
|
||||
* Returns:
|
||||
* index into s[] of match if found, -1 if no match.
|
||||
* Example:
|
||||
* ---
|
||||
* auto s = "abcabcabab";
|
||||
* std.regexp.find(s, "b"); // match, returns 1
|
||||
* std.regexp.find(s, "f"); // no match, returns -1
|
||||
* find(s, RegExp("b")); // 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 i = -1;
|
||||
|
@ -354,24 +383,67 @@ unittest
|
|||
assert(i == -1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Search s[] for last match with pattern[] with attributes[].
|
||||
* Search $(D_PARAM s[]) for last match with $(D_PARAM pattern).
|
||||
* Params:
|
||||
* s = String to search.
|
||||
* pattern = Regular expression pattern.
|
||||
* attributes = Regular expression attributes.
|
||||
* Returns:
|
||||
* index into s[] of match if found, -1 if no match.
|
||||
* Example:
|
||||
* ---
|
||||
* auto s = "abcabcabab";
|
||||
* std.regexp.find(s, "b"); // match, returns 9
|
||||
* std.regexp.find(s, "f"); // no match, returns -1
|
||||
* rfind(s, RegExp("b")); // match, returns 9
|
||||
* 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 i = -1;
|
||||
|
@ -410,16 +482,15 @@ unittest
|
|||
|
||||
/********************************************
|
||||
* 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:
|
||||
* s = String to search.
|
||||
* pattern = Regular expression pattern.
|
||||
* attributes = Regular expression attributes.
|
||||
* Returns:
|
||||
* array of slices into s[]
|
||||
* Example:
|
||||
* ---
|
||||
* foreach (s; split("abcabcabab", "C.", "i"))
|
||||
* foreach (s; split("abcabcabab", RegExp("C.", "i")))
|
||||
* {
|
||||
* 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)
|
||||
{
|
||||
auto r = new RegExp(pattern, attributes);
|
||||
|
@ -475,7 +583,7 @@ unittest
|
|||
* {
|
||||
* 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:
|
||||
|
@ -486,13 +594,9 @@ unittest
|
|||
RegExp search(string s, string pattern, string attributes = null)
|
||||
{
|
||||
auto r = new RegExp(pattern, attributes);
|
||||
|
||||
if (r.test(s))
|
||||
{
|
||||
}
|
||||
else
|
||||
if (!r.test(s))
|
||||
{ delete r;
|
||||
r = null;
|
||||
assert(r is null);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -503,10 +607,10 @@ unittest
|
|||
|
||||
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(m.match(1) == null);
|
||||
assert(m.match(2) == null);
|
||||
assert(m[1] == null);
|
||||
assert(m[2] == null);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
@ -598,7 +702,7 @@ class RegExp
|
|||
* {
|
||||
* 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:
|
||||
|
@ -639,7 +743,7 @@ class RegExp
|
|||
int i;
|
||||
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");
|
||||
else if (i == 1) assert(s == "abc[ab]cabab");
|
||||
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,
|
||||
* null is returned.
|
||||
*/
|
||||
public string match(size_t n)
|
||||
public string opIndex(size_t n)
|
||||
{
|
||||
if (n >= pmatch.length)
|
||||
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.
|
||||
*/
|
||||
|
@ -1255,6 +1373,21 @@ public int test(string s, int startindex)
|
|||
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)
|
||||
{
|
||||
for (; si < input.length; si++)
|
||||
|
@ -3154,17 +3287,17 @@ unittest
|
|||
|
||||
auto m = search("aBC r s", `bc\x20r[\40]s`, "i");
|
||||
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`);
|
||||
assert(m2.match(0)=="7xxyxx");
|
||||
assert(m2[0]=="7xxyxx");
|
||||
// Just check the parsing.
|
||||
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 m5 = search("xxx", `^^\r\n\b{13,}\f{4}\t\v\u02aF3a\w\W`);
|
||||
auto m6 = search("xxy", `.*y`);
|
||||
assert(m6.match(0)=="xxy");
|
||||
assert(m6[0]=="xxy");
|
||||
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 m9 = search("dcbxx", `[-w]`);
|
||||
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.traits;
|
||||
import std.contracts;
|
||||
import std.file, std.typetuple; // for testing only
|
||||
import std.file;
|
||||
import std.typetuple;
|
||||
|
||||
version (DigitalMars)
|
||||
{
|
||||
|
@ -241,7 +242,7 @@ unittest
|
|||
// test write
|
||||
string file = "dmd-build-test.deleteme.txt";
|
||||
FILE* f = fopen(file, "w");
|
||||
assert(f);
|
||||
assert(f, getcwd());
|
||||
write(f, "Hello, ", "world number ", 42, "!");
|
||||
fclose(f) == 0 || assert(false);
|
||||
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
|
||||
|
@ -295,14 +296,19 @@ unittest
|
|||
* equivalent to $(D_PARAM writef(stdout, args)).
|
||||
*
|
||||
|
||||
Warning:
|
||||
IMPORTANT:
|
||||
|
||||
New behavior starting with D 2.006: unlike previous versions,
|
||||
$(D_PARAM writef) (and also $(D_PARAM writefln)) only scans its first
|
||||
string argument for format specifiers, but not subsequent string
|
||||
arguments. Also new in 2.006 is support for positional parameters
|
||||
with $(LINK2 http://www.opengroup.org/onlinepubs/009695399/functions/printf.html,POSIX)
|
||||
syntax.
|
||||
New behavior starting with D 2.006: unlike previous versions,
|
||||
$(D_PARAM writef) (and also $(D_PARAM writefln)) only scans its first
|
||||
string argument for format specifiers, but not subsequent string
|
||||
arguments. This decision was made because the old behavior made it
|
||||
unduly hard to simply print string variables that occasionally
|
||||
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:
|
||||
|
||||
|
@ -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
|
||||
format string. (POSIX leaves this behavior undefined.) The internal
|
||||
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)
|
||||
{
|
||||
FileWriter!(char) w;
|
||||
PrivateFileWriter!(char) w;
|
||||
static const errorMessage =
|
||||
"You must pass a formatting string as the first"
|
||||
" 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
|
||||
* with the character type, e.g. FileWriter!(char),
|
||||
* FileWriter!(wchar), or FileWriter!(dchar). Regardless of
|
||||
* instantiation, FileWriter supports all character widths; it only is
|
||||
* with the character type, e.g. PrivateFileWriter!(char),
|
||||
* PrivateFileWriter!(wchar), or PrivateFileWriter!(dchar). Regardless of
|
||||
* instantiation, PrivateFileWriter supports all character widths; it only is
|
||||
* the most efficient at accepting the character type it was
|
||||
* instantiated with.
|
||||
*
|
||||
* */
|
||||
private struct FileWriter(Char)
|
||||
private struct PrivateFileWriter(Char)
|
||||
{
|
||||
alias Char NativeChar;
|
||||
FILE* backend;
|
||||
|
@ -929,10 +943,36 @@ Example:
|
|||
|
||||
struct lines
|
||||
{
|
||||
FILE * f;
|
||||
dchar terminator = '\n';
|
||||
private FILE * f;
|
||||
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)
|
||||
{
|
||||
// scope(exit) {
|
||||
// if (fileName.length && fclose(f))
|
||||
// StdioException("Could not close file `"~fileName~"'");
|
||||
// }
|
||||
alias ParameterTypeTuple!(dg) Parms;
|
||||
static if (isSomeString!(Parms[$ - 1]))
|
||||
{
|
||||
|
@ -1151,8 +1191,32 @@ struct chunks
|
|||
{
|
||||
private FILE* f;
|
||||
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)
|
||||
{
|
||||
// scope(exit) {
|
||||
// if (fileName.length && fclose(f))
|
||||
// StdioException("Could not close file `"~fileName~"'");
|
||||
// }
|
||||
const maxStackSize = 500 * 1024;
|
||||
ubyte[] buffer = void;
|
||||
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.ctype;
|
||||
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)
|
||||
{
|
||||
|
@ -1539,6 +1542,194 @@ unittest
|
|||
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.
|
||||
* If delimiter[] is null, removes trailing CR, LF, or CRLF, if any.
|
||||
|
@ -1608,6 +1799,23 @@ unittest
|
|||
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.
|
||||
|
@ -3018,7 +3226,7 @@ certain category of characters (e.g. whitespace) when parsing
|
|||
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;
|
||||
foreach (i, c; s)
|
||||
|
|
83
std/traits.d
83
std/traits.d
|
@ -271,6 +271,41 @@ unittest
|
|||
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
|
||||
* conversion of a value of type $(D_PARAM T).
|
||||
|
@ -322,9 +357,6 @@ template ImplicitConversionTargets(T)
|
|||
else static if (is(T == double))
|
||||
alias TypeTuple!(real)
|
||||
ImplicitConversionTargets;
|
||||
// else static if (is(T == real))
|
||||
// alias TypeTuple!()
|
||||
// ImplicitConversionTargets;
|
||||
else static if (is(T == char))
|
||||
alias TypeTuple!(wchar, dchar, byte, ubyte, short, ushort,
|
||||
int, uint, long, ulong, float, double, real)
|
||||
|
@ -356,33 +388,36 @@ unittest
|
|||
|
||||
template isIntegral(T)
|
||||
{
|
||||
static const isIntegral = is(T == byte) || is(T == ubyte) || is(T == short)
|
||||
|| is(T == ushort) || is(T == int) || is(T == uint)
|
||||
|| is(T == long) || is(T == ulong);
|
||||
static const isIntegral = is(T == byte) || is(T == ubyte) || is(T == short)
|
||||
|| is(T == ushort) || is(T == int) || is(T == uint)
|
||||
|| is(T == long) || is(T == ulong);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether T is a built-in floating point type
|
||||
*/
|
||||
|
||||
template isFloatingPoint(T) {
|
||||
static const isFloatingPoint = is(T == float)
|
||||
|| is(T == double) || is(T == real);
|
||||
template isFloatingPoint(T)
|
||||
{
|
||||
static const isFloatingPoint = is(T == float)
|
||||
|| is(T == double) || is(T == real);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether T is a built-in numeric type
|
||||
*/
|
||||
|
||||
template isNumeric(T) {
|
||||
static const isNumeric = isIntegral!(T) || isFloatingPoint!(T);
|
||||
template isNumeric(T)
|
||||
{
|
||||
static const isNumeric = isIntegral!(T) || isFloatingPoint!(T);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether T is one of the built-in string types
|
||||
*/
|
||||
|
||||
template isSomeString(T) {
|
||||
template isSomeString(T)
|
||||
{
|
||||
static const isSomeString = is(T : const(char[]))
|
||||
|| is(T : const(wchar[])) || is(T : const(dchar[]));
|
||||
}
|
||||
|
@ -403,9 +438,8 @@ static assert(isSomeString!(char[4]));
|
|||
|
||||
template isAssociativeArray(T)
|
||||
{
|
||||
static const bool isAssociativeArray
|
||||
= is(typeof(T.keys)) && is(typeof(T.values));
|
||||
// = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T);
|
||||
static const bool isAssociativeArray =
|
||||
is(typeof(T.keys)) && is(typeof(T.values));
|
||||
}
|
||||
|
||||
static assert(!isAssociativeArray!(int));
|
||||
|
@ -414,19 +448,25 @@ static assert(isAssociativeArray!(int[int]));
|
|||
static assert(isAssociativeArray!(int[string]));
|
||||
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)
|
||||
{
|
||||
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[][2]));
|
||||
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[char]));
|
||||
static assert (!isStaticArray!(int[1][]));
|
||||
|
@ -434,6 +474,9 @@ static assert(isStaticArray!(invariant char[13u]));
|
|||
static assert(isStaticArray!(void[0]));
|
||||
static assert(!isStaticArray!(int[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.
|
||||
|
|
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);
|
||||
}
|
||||
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
|
||||
* 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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue