Merge branch 'master' of github.com:D-Programming-Language/phobos

Conflicts:
	posix.mak
This commit is contained in:
Andrei Alexandrescu 2011-04-06 00:32:29 -05:00
commit 055cea0595
15 changed files with 7451 additions and 4778 deletions

16
changelog.dd Normal file
View file

@ -0,0 +1,16 @@
$(VERSION 053, ddd mm, 2011, =================================================,
$(WHATSNEW
$(LI Added bindings for libcurl on Posix: etc.c.curl)
)
$(LIBBUGSFIXED
$(LI $(BUGZILLA 4644): assertExceptionThrown to assert that a particular exception was thrown)
$(LI $(BUGZILLA 4944): Missing tzname even though we have tzset)
$(LI $(BUGZILLA 5451): Three ideas for RedBlackTree)
$(LI $(BUGZILLA 5485): TLS sections handled incorrectly in FreeBSD)
$(LI $(BUGZILLA 5616): std.datetime: not cross-platform)
$(LI $(BUGZILLA 5654): BigInt returns ZERO with strings of single digit number with leading zeros)
$(LI $(BUGZILLA 5731): std.datetime.SysTime prints UTC offsets backwards)
)
)

2193
etc/c/curl.d Normal file

File diff suppressed because it is too large Load diff

View file

@ -165,7 +165,7 @@ STD_MODULES = $(addprefix std/, algorithm array base64 bigint bitmanip \
# Other D modules that aren't under std/ # Other D modules that aren't under std/
EXTRA_MODULES := $(addprefix std/c/, stdarg stdio) $(addprefix etc/c/, \ EXTRA_MODULES := $(addprefix std/c/, stdarg stdio) $(addprefix etc/c/, \
zlib) $(addprefix std/internal/math/, biguintcore biguintnoasm \ zlib) $(addprefix std/internal/math/, biguintcore biguintnoasm \
biguintx86 gammafunction errorfunction) biguintx86 gammafunction errorfunction) $(addprefix etc/c/, curl)
# OS-specific D modules # OS-specific D modules
EXTRA_MODULES_LINUX := $(addprefix std/c/linux/, linux socket) EXTRA_MODULES_LINUX := $(addprefix std/c/linux/, linux socket)
@ -245,9 +245,6 @@ DISABLED_TESTS += std/format
DISABLED_TESTS += std/math DISABLED_TESTS += std/math
# seems to infinite loop, need to reduce # seems to infinite loop, need to reduce
DISABLED_TESTS += std/random
DISABLED_TESTS += std/internal/math/biguintnoasm
$(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : $(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) :
@echo Testing $@ - disabled @echo Testing $@ - disabled
endif endif

View file

@ -489,7 +489,7 @@ $(D array) at position $(D pos).
Example: Example:
--- ---
int[] a = [ 1, 2, 3, 4 ]; int[] a = [ 1, 2, 3, 4 ];
a.insert(2, [ 1, 2 ]); a.insert(2, [ 1, 2 ]);
assert(a == [ 1, 2, 1, 2, 3, 4 ]); assert(a == [ 1, 2, 1, 2, 3, 4 ]);
--- ---
*/ */

View file

@ -66,7 +66,7 @@ private
{ {
MsgType type; MsgType type;
Variant data; Variant data;
this(T...)( MsgType t, T vals ) this(T...)( MsgType t, T vals )
if( T.length < 1 ) if( T.length < 1 )
{ {
@ -95,7 +95,7 @@ private
else else
return data.convertsTo!(Tuple!(T)); return data.convertsTo!(Tuple!(T));
} }
auto get(T...)() auto get(T...)()
{ {
static if( T.length == 1 ) static if( T.length == 1 )
@ -501,6 +501,11 @@ bool receiveTimeout(T...)( long ms, T ops )
return mbox.get( ms * TICKS_PER_MILLI, ops ); return mbox.get( ms * TICKS_PER_MILLI, ops );
} }
/++ ditto +/
bool receiveTimeout(T...)( Duration duration, T ops )
{
return receiveTimeout(duration.total!"msecs"(), ops);
}
unittest unittest
{ {
@ -519,6 +524,11 @@ unittest
{ {
receiveTimeout( 0, (int x) {}, (int x) {} ); receiveTimeout( 0, (int x) {}, (int x) {} );
} ) ); } ) );
assert( __traits( compiles,
{
receiveTimeout( dur!"msecs"(10), (int x) {}, (Variant x) {} );
} ) );
} }
@ -602,6 +612,115 @@ void setMaxMailboxSize( Tid tid, size_t messages, bool function(Tid) onCrowdingD
} }
//////////////////////////////////////////////////////////////////////////////
// Name Registration
//////////////////////////////////////////////////////////////////////////////
private
{
__gshared Tid[string] tidByName;
__gshared string[][Tid] namesByTid;
__gshared Mutex registryLock;
}
shared static this()
{
registryLock = new Mutex;
}
static ~this()
{
auto me = thisTid;
synchronized( registryLock )
{
if( auto allNames = me in namesByTid )
{
foreach( name; *allNames )
tidByName.remove( name );
namesByTid.remove( me );
}
}
}
/**
* Associates name with tid in a process-local map. When the thread
* represented by tid termiantes, any names associated with it will be
* automatically unregistered.
*
* Params:
* name = The name to associate with tid.
* tid = The tid register by name.
*
* Returns:
* true if the name is available and tid is not known to represent a
* defunct thread.
*/
bool register( string name, Tid tid )
{
synchronized( registryLock )
{
if( name in tidByName )
return false;
if( tid.mbox.isClosed )
return false;
namesByTid[tid] ~= name;
tidByName[name] = tid;
return true;
}
}
/**
* Removes the registered name associated with a tid.
*
* Params:
* name = The name to unregister.
*
* Returns:
* true if the name is registered, false if not.
*/
bool unregister( string name )
{
synchronized( registryLock )
{
if( auto tid = name in tidByName )
{
auto allNames = *tid in namesByTid;
auto pos = countUntil( *allNames, name );
remove!(SwapStrategy.unstable)( *allNames, pos );
tidByName.remove( name );
return true;
}
return false;
}
}
/**
* Gets the Tid associated with name.
*
* Params:
* name = The name to locate within the registry.
*
* Returns:
* The associated Tid or Tid.init if name is not registered.
*/
Tid locate( string name )
{
synchronized( registryLock )
{
if( auto tid = name in tidByName )
return *tid;
return Tid.init;
}
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// MessageBox Implementation // MessageBox Implementation
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -627,6 +746,18 @@ private
} }
/*
*
*/
final @property bool isClosed() const
{
synchronized( m_lock )
{
return m_closed;
}
}
/* /*
* Sets a limit on the maximum number of user messages allowed in the * Sets a limit on the maximum number of user messages allowed in the
* mailbox. If this limit is reached, the caller attempting to add * mailbox. If this limit is reached, the caller attempting to add
@ -738,7 +869,7 @@ private
{ {
alias ParameterTypeTuple!(t) Args; alias ParameterTypeTuple!(t) Args;
auto op = ops[i]; auto op = ops[i];
if( msg.convertsTo!(Args) ) if( msg.convertsTo!(Args) )
{ {
static if( is( ReturnType!(t) == bool ) ) static if( is( ReturnType!(t) == bool ) )
@ -765,7 +896,7 @@ private
links.remove( tid ); links.remove( tid );
// Give the owner relationship precedence. // Give the owner relationship precedence.
if( *depends && tid != owner ) if( *depends && tid != owner )
{ {
auto e = new LinkTerminated( tid ); auto e = new LinkTerminated( tid );
if( onStandardMsg( Message( MsgType.standard, e ) ) ) if( onStandardMsg( Message( MsgType.standard, e ) ) )
return true; return true;
@ -818,7 +949,7 @@ private
continue; continue;
} }
list.removeAt( range ); list.removeAt( range );
return true; return true;
} }
range.popFront(); range.popFront();
continue; continue;
@ -982,8 +1113,8 @@ private
{ {
return msg.type == MsgType.priority; return msg.type == MsgType.priority;
} }
pure final bool isLinkDeadMsg( ref Message msg ) pure final bool isLinkDeadMsg( ref Message msg )
{ {
return msg.type == MsgType.linkDead; return msg.type == MsgType.linkDead;

View file

@ -4101,13 +4101,10 @@ struct RBNode(V)
* ignored on insertion. If duplicates are allowed, then new elements are * ignored on insertion. If duplicates are allowed, then new elements are
* inserted after all existing duplicate elements. * inserted after all existing duplicate elements.
*/ */
struct RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string)) if(is(typeof(binaryFun!less(T.init, T.init))))
{ {
static if(is(typeof(less) == string)) alias binaryFun!less _less;
alias binaryFun!(less) _less;
else
alias less _less;
// BUG: this must come first in the struct due to issue 2810 // BUG: this must come first in the struct due to issue 2810
@ -4118,7 +4115,20 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
{ {
Node result; Node result;
static if(!allowDuplicates) static if(!allowDuplicates)
{
bool added = true; bool added = true;
scope(success)
{
if(added)
++_length;
}
}
else
{
scope(success)
++_length;
}
if(!_end.left) if(!_end.left)
{ {
_end.left = result = allocate(n); _end.left = result = allocate(n);
@ -4200,11 +4210,6 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
} }
return false; return false;
} }
private static RedBlackTree create(Elem[] elems...)
{
return RedBlackTree(elems);
}
} }
else else
{ {
@ -4219,10 +4224,12 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
// used for convenience // used for convenience
private alias RBNode!Elem.Node Node; private alias RBNode!Elem.Node Node;
private Node _end; private Node _end;
private size_t _length;
private void _setup() private void _setup()
{ {
assert(!_end); //Make sure that _setup isn't run more than once.
_end = allocate(); _end = allocate();
} }
@ -4307,10 +4314,17 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1, 2, 3, 4, 5); auto ts = new RedBlackTree(1, 2, 3, 4, 5);
assert(ts.length == 5);
auto r = ts[]; auto r = ts[];
assert(std.algorithm.equal(r, cast(T[])[1, 2, 3, 4, 5]));
assert(r.front == 1); static if(less == "a < b")
auto vals = [1, 2, 3, 4, 5];
else
auto vals = [5, 4, 3, 2, 1];
assert(std.algorithm.equal(r, vals));
assert(r.front == vals.front);
assert(r.back != r.front); assert(r.back != r.front);
auto oldfront = r.front; auto oldfront = r.front;
auto oldback = r.back; auto oldback = r.back;
@ -4319,6 +4333,7 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
assert(r.front != r.back); assert(r.front != r.back);
assert(r.front != oldfront); assert(r.front != oldfront);
assert(r.back != oldback); assert(r.back != oldback);
assert(ts.length == 5);
} }
// find a node based on an element value // find a node based on an element value
@ -4368,27 +4383,37 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
return _end.left is null; return _end.left is null;
} }
/++
Returns the number of elements in the container.
Complexity: $(BIGOH 1).
+/
@property size_t length()
{
return _length;
}
/** /**
* Duplicate this container. The resulting container contains a shallow * Duplicate this container. The resulting container contains a shallow
* copy of the elements. * copy of the elements.
* *
* Complexity: $(BIGOH n) * Complexity: $(BIGOH n)
*/ */
RedBlackTree dup() @property RedBlackTree dup()
{ {
RedBlackTree result; return new RedBlackTree(_end.dup(), _length);
result._setup();
result._end = _end.dup();
return result;
} }
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1, 2, 3, 4, 5); auto ts = new RedBlackTree(1, 2, 3, 4, 5);
auto ts2 = ts.dup(); assert(ts.length == 5);
auto ts2 = ts.dup;
assert(ts2.length == 5);
assert(std.algorithm.equal(ts[], ts2[])); assert(std.algorithm.equal(ts[], ts2[]));
ts2.insert(cast(Elem)6); ts2.insert(cast(Elem)6);
assert(!std.algorithm.equal(ts[], ts2[])); assert(!std.algorithm.equal(ts[], ts2[]));
assert(ts.length == 5 && ts2.length == 6);
} }
/** /**
@ -4421,11 +4446,12 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
return _end.prev.value; return _end.prev.value;
} }
/** /++
* Check to see if an element exists in the container $(D in) operator. Check to see if the given element exists in the
* container.
* Complexity: $(BIGOH log(n))
*/ Complexity: $(BIGOH log(n))
+/
bool opBinaryRight(string op)(Elem e) if (op == "in") bool opBinaryRight(string op)(Elem e) if (op == "in")
{ {
return _find(e) !is null; return _find(e) !is null;
@ -4433,19 +4459,28 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1, 2, 3, 4, 5); auto ts = new RedBlackTree(1, 2, 3, 4, 5);
assert(cast(Elem)3 in ts); assert(cast(Elem)3 in ts);
assert(cast(Elem)6 !in ts); assert(cast(Elem)6 !in ts);
} }
/** /**
* Clear the container of all elements * Removes all elements from the container.
* *
* Complexity: $(BIGOH 1) * Complexity: $(BIGOH 1)
*/ */
void clear() void clear()
{ {
_end.left = null; _end.left = null;
_length = 0;
}
static if(doUnittest) unittest
{
auto ts = new RedBlackTree(1,2,3,4,5);
assert(ts.length == 5);
ts.clear();
assert(ts.empty && ts.length == 0);
} }
/** /**
@ -4500,10 +4535,33 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1,2,3,4,5); auto ts = new RedBlackTree(2,1,3,4,5,2,5);
assert(ts.stableInsert(cast(Elem[])[6, 7, 8, 9, 10]) == 5); static if(allowDuplicates)
assert(ts.stableInsert(cast(Elem)11) == 1); {
assert(ts.arrayEqual([1,2,3,4,5,6,7,8,9,10,11])); assert(ts.length == 7);
assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 6);
assert(ts.length == 13);
assert(ts.stableInsert(cast(Elem)11) == 1 && ts.length == 14);
assert(ts.stableInsert(cast(Elem)7) == 1 && ts.length == 15);
static if(less == "a < b")
assert(ts.arrayEqual([1,2,2,3,4,5,5,6,7,7,8,8,9,10,11]));
else
assert(ts.arrayEqual([11,10,9,8,8,7,7,6,5,5,4,3,2,2,1]));
}
else
{
assert(ts.length == 5);
assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 5);
assert(ts.length == 10);
assert(ts.stableInsert(cast(Elem)11) == 1 && ts.length == 11);
assert(ts.stableInsert(cast(Elem)7) == 0 && ts.length == 11);
static if(less == "a < b")
assert(ts.arrayEqual([1,2,3,4,5,6,7,8,9,10,11]));
else
assert(ts.arrayEqual([11,10,9,8,7,6,5,4,3,2,1]));
}
} }
/** /**
@ -4513,6 +4571,8 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
*/ */
Elem removeAny() Elem removeAny()
{ {
scope(success)
--_length;
auto n = _end.leftmost; auto n = _end.leftmost;
auto result = n.value; auto result = n.value;
n.remove(_end); n.remove(_end);
@ -4523,8 +4583,10 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1,2,3,4,5); auto ts = new RedBlackTree(1,2,3,4,5);
assert(ts.length == 5);
auto x = ts.removeAny(); auto x = ts.removeAny();
assert(ts.length == 4);
Elem[] arr; Elem[] arr;
foreach(Elem i; 1..6) foreach(Elem i; 1..6)
if(i != x) arr ~= i; if(i != x) arr ~= i;
@ -4538,6 +4600,8 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
*/ */
void removeFront() void removeFront()
{ {
scope(success)
--_length;
_end.leftmost.remove(_end); _end.leftmost.remove(_end);
version(RBDoChecks) version(RBDoChecks)
check(); check();
@ -4550,6 +4614,8 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
*/ */
void removeBack() void removeBack()
{ {
scope(success)
--_length;
_end.prev.remove(_end); _end.prev.remove(_end);
version(RBDoChecks) version(RBDoChecks)
check(); check();
@ -4557,19 +4623,29 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1,2,3,4,5); auto ts = new RedBlackTree(1,2,3,4,5);
assert(ts.length == 5);
ts.removeBack(); ts.removeBack();
assert(ts.arrayEqual([1,2,3,4])); assert(ts.length == 4);
static if(less == "a < b")
assert(ts.arrayEqual([1,2,3,4]));
else
assert(ts.arrayEqual([2,3,4,5]));
ts.removeFront(); ts.removeFront();
assert(ts.arrayEqual([2,3,4])); assert(ts.arrayEqual([2,3,4]) && ts.length == 3);
} }
/** /++
* Remove the given range from the container. Returns a range containing Removes the given range from the container.
* all the elements that were after the given range.
* Returns: A range containing all of the elements that were after the
* Complexity: $(BIGOH m * log(n)) given range.
*/
Complexity: $(BIGOH m * log(n)) (where m is the number of elements in
the range)
+/
Range remove(Range r) Range remove(Range r)
{ {
auto b = r._begin; auto b = r._begin;
@ -4577,6 +4653,7 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
while(b !is e) while(b !is e)
{ {
b = b.remove(_end); b = b.remove(_end);
--_length;
} }
version(RBDoChecks) version(RBDoChecks)
check(); check();
@ -4585,13 +4662,159 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1,2,3,4,5); auto ts = new RedBlackTree(1,2,3,4,5);
assert(ts.length == 5);
auto r = ts[]; auto r = ts[];
r.popFront(); r.popFront();
r.popBack(); r.popBack();
assert(ts.length == 5);
auto r2 = ts.remove(r); auto r2 = ts.remove(r);
assert(ts.length == 2);
assert(ts.arrayEqual([1,5])); assert(ts.arrayEqual([1,5]));
assert(std.algorithm.equal(r2, [5]));
static if(less == "a < b")
assert(std.algorithm.equal(r2, [5]));
else
assert(std.algorithm.equal(r2, [1]));
}
/++
Removes the given $(D Take!Range) from the container
Returns: A range containing all of the elements that were after the
given range.
Complexity: $(BIGOH m * log(n)) (where m is the number of elements in
the range)
+/
Range remove(Take!Range r)
{
auto b = r.original._begin;
while(!r.empty)
r.popFront(); // move take range to its last element
auto e = r.original._begin;
while(b != e)
{
b = b.remove(_end);
--_length;
}
return Range(e, _end);
}
static if(doUnittest) unittest
{
auto ts = new RedBlackTree(1,2,3,4,5);
auto r = ts[];
r.popFront();
assert(ts.length == 5);
auto r2 = ts.remove(take(r, 0));
static if(less == "a < b")
{
assert(std.algorithm.equal(r2, [2,3,4,5]));
auto r3 = ts.remove(take(r, 2));
assert(ts.arrayEqual([1,4,5]) && ts.length == 3);
assert(std.algorithm.equal(r3, [4,5]));
}
else
{
assert(std.algorithm.equal(r2, [4,3,2,1]));
auto r3 = ts.remove(take(r, 2));
assert(ts.arrayEqual([5,2,1]) && ts.length == 3);
assert(std.algorithm.equal(r3, [2,1]));
}
}
/++
Removes elements from the container that are equal to the given values
according to the less comparator. One element is removed for each value
given which is in the container. If $(D allowDuplicates) is true,
duplicates are removed only if duplicate values are given.
Returns: The number of elements removed.
Complexity: $(BIGOH m log(n)) (where m is the number of elements to remove)
Examples:
--------------------
auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7);
rbt.removeKey(1, 4, 7);
assert(std.algorithm.equal(rbt[], [0, 1, 1, 5]));
rbt.removeKey(1, 1, 0);
assert(std.algorithm.equal(rbt[], [5]));
--------------------
+/
size_t removeKey(U)(U[] elems...)
if(isImplicitlyConvertible!(U, Elem))
{
immutable lenBefore = length;
foreach(e; elems)
{
auto beg = _firstGreaterEqual(e);
if(beg is _end || _less(e, beg.value))
// no values are equal
continue;
beg.remove(_end);
--_length;
}
return lenBefore - length;
}
/++ Ditto +/
size_t removeKey(Stuff)(Stuff stuff)
if(isInputRange!Stuff &&
isImplicitlyConvertible!(ElementType!Stuff, Elem) &&
!is(Stuff == Elem[]))
{
//We use array in case stuff is a Range from this RedBlackTree - either
//directly or indirectly.
return removeKey(array(stuff));
}
static if(doUnittest) unittest
{
auto rbt = new RedBlackTree(5, 4, 3, 7, 2, 1, 7, 6, 2, 19, 45);
static if(allowDuplicates)
{
assert(rbt.length == 11);
assert(rbt.removeKey(cast(Elem)4) == 1 && rbt.length == 10);
assert(rbt.arrayEqual([1,2,2,3,5,6,7,7,19,45]) && rbt.length == 10);
assert(rbt.removeKey(cast(Elem)6, cast(Elem)2, cast(Elem)1) == 3);
assert(rbt.arrayEqual([2,3,5,7,7,19,45]) && rbt.length == 7);
assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 7);
assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 4);
static if(less == "a < b")
assert(std.algorithm.equal(rbt[], [7,7,19,45]));
else
assert(std.algorithm.equal(rbt[], [7,5,3,2]));
}
else
{
assert(rbt.length == 9);
assert(rbt.removeKey(cast(Elem)4) == 1 && rbt.length == 8);
assert(rbt.arrayEqual([1,2,3,5,6,7,19,45]));
assert(rbt.removeKey(cast(Elem)6, cast(Elem)2, cast(Elem)1) == 3);
assert(rbt.arrayEqual([3,5,7,19,45]) && rbt.length == 5);
assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 5);
assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 2);
static if(less == "a < b")
assert(std.algorithm.equal(rbt[], [19,45]));
else
assert(std.algorithm.equal(rbt[], [5,3]));
}
} }
// find the first node where the value is > e // find the first node where the value is > e
@ -4681,18 +4904,28 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
static if(doUnittest) unittest static if(doUnittest) unittest
{ {
auto ts = create(1, 2, 3, 4, 5); auto ts = new RedBlackTree(1, 2, 3, 4, 5);
auto r1 = ts.lowerBound(3); auto rl = ts.lowerBound(3);
assert(std.algorithm.equal(r1, [1,2])); auto ru = ts.upperBound(3);
auto r2 = ts.upperBound(3); auto re = ts.equalRange(3);
assert(std.algorithm.equal(r2, [4,5]));
auto r3 = ts.equalRange(3); static if(less == "a < b")
assert(std.algorithm.equal(r3, [3])); {
assert(std.algorithm.equal(rl, [1,2]));
assert(std.algorithm.equal(ru, [4,5]));
}
else
{
assert(std.algorithm.equal(rl, [5,4]));
assert(std.algorithm.equal(ru, [2,1]));
}
assert(std.algorithm.equal(re, [3]));
} }
version(RBDoChecks) version(RBDoChecks)
{ {
/** /*
* Print the tree. This prints a sideways view of the tree in ASCII form, * Print the tree. This prints a sideways view of the tree in ASCII form,
* with the number of indentations representing the level of the nodes. * with the number of indentations representing the level of the nodes.
* It does not print values, only the tree structure and color of nodes. * It does not print values, only the tree structure and color of nodes.
@ -4717,7 +4950,7 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
writeln(); writeln();
} }
/** /*
* Check the tree for validity. This is called after every add or remove. * Check the tree for validity. This is called after every add or remove.
* This should only be enabled to debug the implementation of the RB Tree. * This should only be enabled to debug the implementation of the RB Tree.
*/ */
@ -4773,6 +5006,11 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
} }
} }
/+
For the moment, using templatized contstructors doesn't seem to work
very well (likely due to bug# 436 and/or bug# 1528). The redBlackTree
helper function seems to do the job well enough though.
/** /**
* Constructor. Pass in an array of elements, or individual elements to * Constructor. Pass in an array of elements, or individual elements to
* initialize the tree with. * initialize the tree with.
@ -4791,17 +5029,136 @@ if (is(typeof(less(T.init, T.init)) == bool) || is(typeof(less) == string))
_setup(); _setup();
stableInsert(stuff); stableInsert(stuff);
} }
+/
/++ +/
this()
{
_setup();
}
/++
Constructor. Pass in an array of elements, or individual elements to
initialize the tree with.
+/
this(Elem[] elems...)
{
_setup();
stableInsert(elems);
}
private this(Node end, size_t length)
{
_end = end;
_length = length;
}
}
//Verify Example for removeKey.
unittest
{
auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7);
rbt.removeKey(1, 4, 7);
assert(std.algorithm.equal(rbt[], [0, 1, 1, 5]));
rbt.removeKey(1, 1, 0);
assert(std.algorithm.equal(rbt[], [5]));
} }
unittest unittest
{ {
RedBlackTree!uint rt1; void test(T)()
RedBlackTree!int rt2; {
RedBlackTree!ushort rt3; auto rt1 = new RedBlackTree!(T, "a < b", false)();
RedBlackTree!short rt4; auto rt2 = new RedBlackTree!(T, "a < b", true)();
RedBlackTree!ubyte rt5; auto rt3 = new RedBlackTree!(T, "a > b", false)();
RedBlackTree!byte rt6; auto rt4 = new RedBlackTree!(T, "a > b", true)();
}
test!long();
test!ulong();
test!int();
test!uint();
test!short();
test!ushort();
test!byte();
test!byte();
}
/++
Convenience function for creating a $(D RedBlackTree!E) from a list of
values.
Examples:
--------------------
auto rbt1 = redBlackTree(0, 1, 5, 7);
auto rbt2 = redBlackTree!string("hello", "world");
auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5);
auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7);
auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9);
--------------------
+/
auto redBlackTree(E)(E[] elems...)
{
return new RedBlackTree!E(elems);
}
/++ Ditto +/
auto redBlackTree(bool allowDuplicates, E)(E[] elems...)
{
return new RedBlackTree!(E, "a < b", allowDuplicates)(elems);
}
/++ Ditto +/
auto redBlackTree(alias less, E)(E[] elems...)
{
return new RedBlackTree!(E, less)(elems);
}
/++ Ditto +/
auto redBlackTree(alias less, bool allowDuplicates, E)(E[] elems...)
if(is(typeof(binaryFun!less(E.init, E.init))))
{
//We shouldn't need to instantiate less here, but for some reason,
//dmd can't handle it if we don't (even though the template which
//takes less but not allowDuplicates works just fine).
return new RedBlackTree!(E, binaryFun!less, allowDuplicates)(elems);
}
//Verify Examples.
unittest
{
auto rbt1 = redBlackTree(0, 1, 5, 7);
auto rbt2 = redBlackTree!string("hello", "world");
auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5);
auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7);
auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9);
}
//Combinations not in examples.
unittest
{
auto rbt1 = redBlackTree!(true, string)("hello", "hello");
auto rbt2 = redBlackTree!((a, b){return a < b;}, double)(5.1, 2.3);
auto rbt3 = redBlackTree!("a > b", true, string)("hello", "world");
}
unittest
{
auto rt1 = redBlackTree(5, 4, 3, 2, 1);
assert(rt1.length == 5);
assert(array(rt1[]) == [1, 2, 3, 4, 5]);
auto rt2 = redBlackTree!"a > b"(1.1, 2.1);
assert(rt2.length == 2);
assert(array(rt2[]) == [2.1, 1.1]);
auto rt3 = redBlackTree!true(5, 5, 4);
assert(rt3.length == 3);
assert(array(rt3[]) == [4, 5, 5]);
auto rt4 = redBlackTree!string("hello", "hello");
assert(rt4.length == 1);
assert(array(rt4[]) == ["hello"]);
} }
version(unittest) struct UnittestMe { version(unittest) struct UnittestMe {

File diff suppressed because it is too large Load diff

View file

@ -1,79 +1,354 @@
// Written in the D programming language. // Written in the D programming language.
/** /++
* This module defines tools related to exceptions and general error This module defines functions related to exceptions and general error
* handling. handling. It also defines functions intended to aid in unit testing.
*
* Macros: Synopsis of some of std.exception's functions:
* WIKI = Phobos/StdException --------------------
* string synopsis()
* Synopsis: {
* FILE* f = enforce(fopen("some/file"));
* ---- // f is not null from here on
* string synopsis() FILE* g = enforceEx!(WriteException)(fopen("some/other/file", "w"));
* { // g is not null from here on
* FILE* f = enforce(fopen("some/file"));
* // f is not null from here on Exception e = collectException(write(g, readln(f)));
* FILE* g = enforceEx!(WriteException)(fopen("some/other/file", "w")); if (e)
* // g is not null from here on {
* Exception e = collectException(write(g, readln(f))); ... an exception occurred...
* if (e) ... We have the exception to play around with...
* { }
* ... an exception occurred...
* } string msg = collectExceptionMsg(write(g, readln(f)));
* char[] line; if (msg)
* enforce(readln(f, line)); {
* return assumeUnique(line); ... an exception occurred...
* } ... We have the message from the exception but not the exception...
* ---- }
*
* Copyright: Copyright Andrei Alexandrescu 2008-. char[] line;
* License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) enforce(readln(f, line));
* Authors: $(WEB erdani.org, Andrei Alexandrescu) return assumeUnique(line);
* Source: $(PHOBOSSRC std/_exception.d) }
*/ --------------------
Macros:
WIKI = Phobos/StdException
Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-.
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0)
Authors: $(WEB erdani.org, Andrei Alexandrescu) and Jonathan M Davis
Source: $(PHOBOSSRC std/_exception.d)
+/
module std.exception; module std.exception;
import std.array, std.c.string, std.conv, std.range, std.string, std.traits; import std.array, std.c.string, std.conv, std.range, std.string, std.traits;
import core.stdc.errno; import core.exception, core.stdc.errno;
version(unittest) version(unittest)
{ {
import std.datetime;
import std.stdio; import std.stdio;
} }
/* /++
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com Asserts that the given expression does $(I not) throw the given type
* Written by Andrei Alexandrescu, www.erdani.org of $(D Throwable). If a $(D Throwable) of the given type is thrown,
* it is caught and does not escape assertNotThrown. Rather, an
* This software is provided 'as-is', without any express or implied $(D AssertError) is thrown. However, any other $(D Throwable)s will escape.
* 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.
*/
/** Params:
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws T = The $(D Throwable) to test for.
* $(D_PARAM new Exception(msg)). expression = The expression to test.
* Example: msg = Optional message to output on test failure.
* ----
* auto f = enforce(fopen("data.txt"));
* auto line = readln(f);
* enforce(line.length); // expect a non-empty line
* ----
*/
Throws:
$(D AssertError) if the given $(D Throwable) is thrown.
Examples:
--------------------
assertNotThrown!TimeException(std.datetime.TimeOfDay(0, 0, 0));
assertNotThrown(std.datetime.TimeOfDay(23, 59, 59)); //Exception is default.
assert(collectExceptionMsg!AssertError(assertNotThrown!TimeException(
std.datetime.TimeOfDay(12, 0, 60))) ==
`assertNotThrown failed: TimeException was thrown.`);
--------------------
+/
void assertNotThrown(T : Throwable = Exception, E)
(lazy E expression,
string msg = null,
string file = __FILE__,
size_t line = __LINE__)
{
try
expression();
catch(T t)
{
immutable tail = msg.empty ? "." : ": " ~ msg;
throw new AssertError(format("assertNotThrown failed: %s was thrown%s",
T.stringof,
tail),
file,
line,
t);
}
}
//Verify Examples
unittest
{
assertNotThrown!TimeException(std.datetime.TimeOfDay(0, 0, 0));
assertNotThrown(std.datetime.TimeOfDay(23, 59, 59)); //Exception is default.
assert(collectExceptionMsg!AssertError(assertNotThrown!TimeException(
std.datetime.TimeOfDay(12, 0, 60))) ==
`assertNotThrown failed: TimeException was thrown.`);
}
unittest
{
void throwEx(Throwable t) { throw t; }
void nothrowEx() { }
try
assertNotThrown!Exception(nothrowEx());
catch(AssertError)
assert(0);
try
assertNotThrown!Exception(nothrowEx(), "It's a message");
catch(AssertError)
assert(0);
try
assertNotThrown!AssertError(nothrowEx());
catch(AssertError)
assert(0);
try
assertNotThrown!AssertError(nothrowEx(), "It's a message");
catch(AssertError)
assert(0);
{
bool thrown = false;
try
{
assertNotThrown!Exception(
throwEx(new Exception("It's an Exception")));
}
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
{
assertNotThrown!Exception(
throwEx(new Exception("It's an Exception")), "It's a message");
}
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
{
assertNotThrown!AssertError(
throwEx(new AssertError("It's an AssertError",
__FILE__,
__LINE__)));
}
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
{
assertNotThrown!AssertError(
throwEx(new AssertError("It's an AssertError",
__FILE__,
__LINE__)),
"It's a message");
}
catch(AssertError)
thrown = true;
assert(thrown);
}
}
/++
Asserts that the given expression throws the given type of $(D Throwable).
The $(D Throwable) is caught and does not escape assertThrown. However,
any other $(D Throwable)s $(I will) escape, and if no $(D Throwable)
of the given type is thrown, then an $(D AssertError) is thrown.
Params:
T = The $(D Throwable) to test for.
expression = The expression to test.
msg = Optional message to output on test failure.
Throws:
$(D AssertError) if the given $(D Throwable) is not thrown.
Examples:
--------------------
assertThrown!TimeException(std.datetime.TimeOfDay(-1, 15, 30));
assertThrown(std.datetime.TimeOfDay(12, 15, 60)); //Exception is default.
assert(collectExceptionMsg!AssertError(assertThrown!AssertError(
std.datetime.TimeOfDay(12, 0, 0))) ==
`assertThrown failed: No AssertError was thrown.`);
--------------------
+/
void assertThrown(T : Throwable = Exception, E)
(lazy E expression,
string msg = null,
string file = __FILE__,
size_t line = __LINE__)
{
bool thrown = false;
try
expression();
catch(T t)
thrown = true;
if(!thrown)
{
immutable tail = msg.empty ? "." : ": " ~ msg;
throw new AssertError(format("assertThrown failed: No %s was thrown%s",
T.stringof,
tail),
file,
line);
}
}
//Verify Examples
unittest
{
assertThrown!TimeException(std.datetime.TimeOfDay(-1, 15, 30));
assertThrown(std.datetime.TimeOfDay(12, 15, 60)); //Exception is default.
assert(collectExceptionMsg!AssertError(assertThrown!AssertError(
std.datetime.TimeOfDay(12, 0, 0))) ==
`assertThrown failed: No AssertError was thrown.`);
}
unittest
{
void throwEx(Throwable t) { throw t; }
void nothrowEx() { }
try
assertThrown!Exception(throwEx(new Exception("It's an Exception")));
catch(AssertError)
assert(0);
try
{
assertThrown!Exception(throwEx(new Exception("It's an Exception")),
"It's a message");
}
catch(AssertError)
assert(0);
try
{
assertThrown!AssertError(throwEx(new AssertError("It's an AssertError",
__FILE__,
__LINE__)));
}
catch(AssertError)
assert(0);
try
{
assertThrown!AssertError(throwEx(new AssertError("It's an AssertError",
__FILE__,
__LINE__)),
"It's a message");
}
catch(AssertError)
assert(0);
{
bool thrown = false;
try
assertThrown!Exception(nothrowEx());
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
assertThrown!Exception(nothrowEx(), "It's a message");
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
assertThrown!AssertError(nothrowEx());
catch(AssertError)
thrown = true;
assert(thrown);
}
{
bool thrown = false;
try
assertThrown!AssertError(nothrowEx(), "It's a message");
catch(AssertError)
thrown = true;
assert(thrown);
}
}
/++
If $(D !value) is true, $(D value) is returned. Otherwise,
$(D new Exception(msg)) is thrown.
Note:
$(D enforce) is used to throw exceptions and is therefore intended to
aid in error handling. It is $(I not) intended for verifying the logic
of your program. That is what $(D assert) is for. Also, do not use
$(D enforce) inside of contracts (i.e. inside of $(D in) and $(D out)
blocks and $(D invariant)s), because they will be compiled out when
compiling with $(I -release). Use $(D assert) in contracts.
Example:
--------------------
auto f = enforce(fopen("data.txt"));
auto line = readln(f);
enforce(line.length, "Expected a non-empty line."));
--------------------
+/
T enforce(T, string file = __FILE__, int line = __LINE__) T enforce(T, string file = __FILE__, int line = __LINE__)
(T value, lazy const(char)[] msg = null) (T value, lazy const(char)[] msg = null)
{ {
@ -81,6 +356,10 @@ T enforce(T, string file = __FILE__, int line = __LINE__)
return value; return value;
} }
/++
If $(D !value) is true, $(D value) is returned. Otherwise, the given
delegate is called.
+/
T enforce(T, string file = __FILE__, int line = __LINE__) T enforce(T, string file = __FILE__, int line = __LINE__)
(T value, scope void delegate() dg) (T value, scope void delegate() dg)
{ {
@ -110,17 +389,16 @@ unittest
} }
} }
/** /++
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws If $(D !value) is true, $(D value) is returned. Otherwise, $(D ex) is thrown.
* $(D_PARAM ex).
* Example:
* ----
* auto f = enforce(fopen("data.txt"));
* auto line = readln(f);
* enforce(line.length, new IOException); // expect a non-empty line
* ----
*/
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 Throwable ex) T enforce(T)(T value, lazy Throwable ex)
{ {
if (!value) throw ex(); if (!value) throw ex();
@ -140,20 +418,18 @@ unittest
} }
} }
/** /++
If $(D value) is nonzero, returns it. Otherwise, throws $(D new If $(D !value) is true, $(D value) is returned. Otherwise,
ErrnoException(msg)). The $(D ErrnoException) class assumes that the $(D new ErrnoException(msg)) is thrown. $(D ErrnoException) assumes that the
last operation has set $(D errno) to an error code. last operation set $(D errno) to an error code.
*
* Example:
*
* ----
* auto f = errnoEnforce(fopen("data.txt"));
* auto line = readln(f);
* enforce(line.length); // expect a non-empty line
* ----
*/
Example:
--------------------
auto f = errnoEnforce(fopen("data.txt"));
auto line = readln(f);
enforce(line.length); // expect a non-empty line
--------------------
+/
T errnoEnforce(T, string file = __FILE__, int line = __LINE__) T errnoEnforce(T, string file = __FILE__, int line = __LINE__)
(T value, lazy string msg = null) (T value, lazy string msg = null)
{ {
@ -161,24 +437,21 @@ T errnoEnforce(T, string file = __FILE__, int line = __LINE__)
return value; return value;
} }
/** /++
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws If $(D !value) is true, $(D value) is returned. Otherwise, $(D new E(msg))
* $(D_PARAM new E(msg)). is thrown.
* Example:
* ----
* auto f = enforceEx!(FileMissingException)(fopen("data.txt"));
* auto line = readln(f);
* enforceEx!(DataCorruptionException)(line.length);
* ----
*/
template enforceEx(E) Example:
--------------------
auto f = enforceEx!FileMissingException(fopen("data.txt"));
auto line = readln(f);
enforceEx!DataCorruptionException(line.length);
--------------------
+/
T enforceEx(E, T)(T value, lazy string msg = "")
{ {
T enforceEx(T)(T value, lazy string msg = "") if (!value) throw new E(msg);
{ return value;
if (!value) throw new E(msg);
return value;
}
} }
unittest unittest
@ -196,25 +469,37 @@ unittest
} }
} }
/** /++
* Evaluates $(D_PARAM expression). If evaluation throws an exception, Catches and returns the exception thrown from the given expression.
* return that exception. Otherwise, deposit the resulting value in If no exception is thrown, then null is returned and $(D result) is
* $(D_PARAM target) and return $(D_PARAM null). set to the result of the expression.
* Example:
* ----
* int[] a = new int[3];
* int b;
* assert(collectException(a[4], b));
* ----
*/
Exception collectException(T)(lazy T expression, ref T target) Note that while $(D collectException) $(I can) be used to collect any
$(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
catch anything that is neither an $(D Exception) nor a type derived from
$(D Exception). So, do not use $(D collectException) to collect
non-$(D Exception)s unless you're sure that that's what you really want to
do.
Params:
T = The type of exception to catch.
expression = The expression which may throw an exception.
result = The result of the expression if no exception is thrown.
Example:
--------------------
int[] a = new int[3];
int b;
assert(collectException(a[4], b));
--------------------
+/
T collectException(T = Exception, E)(lazy E expression, ref E result)
{ {
try try
{ {
target = expression(); result = expression();
} }
catch (Exception e) catch (T e)
{ {
return e; return e;
} }
@ -229,20 +514,31 @@ unittest
assert(collectException(foo(), b)); assert(collectException(foo(), b));
} }
/** Evaluates $(D_PARAM expression). If evaluation throws an /++
* exception, return that exception. Otherwise, return $(D_PARAM Catches and returns the exception thrown from the given expression.
* null). $(D_PARAM T) can be $(D_PARAM void). If no exception is thrown, then null is returned. $(D E) can be
*/ $(D void).
Exception collectException(T)(lazy T expression) Note that while $(D collectException) $(I can) be used to collect any
$(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
catch anything that is neither an $(D Exception) nor a type derived from
$(D Exception). So, do not use $(D collectException) to collect
non-$(D Exception)s unless you're sure that that's what you really want to
do.
Params:
T = The type of exception to catch.
expression = The expression which may throw an exception.
+/
T collectException(T : Throwable = Exception, E)(lazy E expression)
{ {
try try
{ {
expression(); expression();
} }
catch (Exception e) catch (T t)
{ {
return e; return t;
} }
return null; return null;
} }
@ -253,20 +549,82 @@ unittest
assert(collectException(foo())); assert(collectException(foo()));
} }
/++
Catches the exception thrown from the given expression and returns the
msg property of that exception. If no exception is thrown, then null is
returned. $(D E) can be $(D void).
If an exception is thrown but it has an empty message, then
$(D emptyExceptionMsg) is returned.
Note that while $(D collectExceptionMsg) $(I can) be used to collect any
$(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
catch anything that is neither an $(D Exception) nor a type derived from
$(D Exception). So, do not use $(D collectExceptionMsg) to collect
non-$(D Exception)s unless you're sure that that's what you really want to
do.
Params:
T = The type of exception to catch.
expression = The expression which may throw an exception.
Examples:
--------------------
void throwFunc() {throw new Exception("My Message.");}
assert(collectExceptionMsg(throwFunc()) == "My Message.");
void nothrowFunc() {}
assert(collectExceptionMsg(nothrowFunc()) is null);
void throwEmptyFunc() {throw new Exception("");}
assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg);
--------------------
+/
string collectExceptionMsg(T = Exception, E)(lazy E expression)
{
try
{
expression();
return cast(string)null;
}
catch(T e)
return e.msg.empty ? emptyExceptionMsg : e.msg;
}
//Verify Examples.
unittest
{
void throwFunc() {throw new Exception("My Message.");}
assert(collectExceptionMsg(throwFunc()) == "My Message.");
void nothrowFunc() {}
assert(collectExceptionMsg(nothrowFunc()) is null);
void throwEmptyFunc() {throw new Exception("");}
assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg);
}
/++
Value that collectExceptionMsg returns when it catches an exception
with an empty exception message.
+/
enum emptyExceptionMsg = "<Empty Exception Message>";
/** /**
* Casts a mutable array to an immutable array in an idiomatic * Casts a mutable array to an immutable array in an idiomatic
* manner. Technically, $(D_PARAM assumeUnique) just inserts a cast, * manner. Technically, $(D assumeUnique) just inserts a cast,
* but its name documents assumptions on the part of the * but its name documents assumptions on the part of the
* caller. $(D_PARAM assumeUnique(arr)) should only be called when * caller. $(D assumeUnique(arr)) should only be called when
* there are no more active mutable aliases to elements of $(D_PARAM * there are no more active mutable aliases to elements of $(D
* arr). To strenghten this assumption, $(D_PARAM assumeUnique(arr)) * arr). To strenghten this assumption, $(D assumeUnique(arr))
* also clears $(D_PARAM arr) before returning. Essentially $(D_PARAM * also clears $(D arr) before returning. Essentially $(D
* assumeUnique(arr)) indicates commitment from the caller that there * assumeUnique(arr)) indicates commitment from the caller that there
* is no more mutable access to any of $(D_PARAM arr)'s elements * is no more mutable access to any of $(D arr)'s elements
* (transitively), and that all future accesses will be done through * (transitively), and that all future accesses will be done through
* the immutable array returned by $(D_PARAM assumeUnique). * the immutable array returned by $(D assumeUnique).
* *
* Typically, $(D_PARAM assumeUnique) is used to return arrays from * Typically, $(D assumeUnique) is used to return arrays from
* functions that have allocated and built them. * functions that have allocated and built them.
* *
* Example: * Example:
@ -283,10 +641,10 @@ unittest
* } * }
* ---- * ----
* *
* The use in the example above is correct because $(D_PARAM result) * The use in the example above is correct because $(D result)
* was private to $(D_PARAM letters) and is unaccessible in writing * was private to $(D letters) and is unaccessible in writing
* after the function returns. The following example shows an * after the function returns. The following example shows an
* incorrect use of $(D_PARAM assumeUnique). * incorrect use of $(D assumeUnique).
* *
* Bad: * Bad:
* *
@ -307,7 +665,7 @@ unittest
* *
* The example above wreaks havoc on client code because it is * The example above wreaks havoc on client code because it is
* modifying arrays that callers considered immutable. To obtain an * modifying arrays that callers considered immutable. To obtain an
* immutable array from the writable array $(D_PARAM buffer), replace * immutable array from the writable array $(D buffer), replace
* the last line with: * the last line with:
* ---- * ----
* return to!(string)(sneaky); // not that sneaky anymore * return to!(string)(sneaky); // not that sneaky anymore
@ -316,12 +674,12 @@ unittest
* The call will duplicate the array appropriately. * The call will duplicate the array appropriately.
* *
* Checking for uniqueness during compilation is possible in certain * Checking for uniqueness during compilation is possible in certain
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in * cases (see the $(D unique) and $(D lent) keywords in
* the $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava) * the $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava)
* language), but complicates the language considerably. The downside * language), but complicates the language considerably. The downside
* of $(D_PARAM assumeUnique)'s convention-based usage is that at this * of $(D assumeUnique)'s convention-based usage is that at this
* time there is no formal checking of the correctness of the * time there is no formal checking of the correctness of the
* assumption; on the upside, the idiomatic use of $(D_PARAM * assumption; on the upside, the idiomatic use of $(D
* assumeUnique) is simple and rare enough to be tolerable. * assumeUnique) is simple and rare enough to be tolerable.
* *
*/ */
@ -429,7 +787,7 @@ unittest
} }
/********************* /*********************
* Thrown if errors that set $(D errno) happen. * Thrown if errors that set $(D errno) occur.
*/ */
class ErrnoException : Exception class ErrnoException : Exception
{ {

View file

@ -1612,7 +1612,7 @@ version(Windows) void mkdir(in char[] pathname)
version(Posix) void mkdir(in char[] pathname) version(Posix) void mkdir(in char[] pathname)
{ {
cenforce(core.sys.posix.sys.stat.mkdir(toStringz(pathname), 0777) == 0, cenforce(core.sys.posix.sys.stat.mkdir(toStringz(pathname), octal!777) == 0,
pathname); pathname);
} }

View file

@ -1942,7 +1942,7 @@ here:
stream.clear; formattedWrite(stream, "%#X", 0xABCD); stream.clear; formattedWrite(stream, "%#X", 0xABCD);
assert(stream.data == "0XABCD"); assert(stream.data == "0XABCD");
stream.clear; formattedWrite(stream, "%#o", 012345); stream.clear; formattedWrite(stream, "%#o", octal!12345);
assert(stream.data == "012345"); assert(stream.data == "012345");
stream.clear; formattedWrite(stream, "%o", 9); stream.clear; formattedWrite(stream, "%o", 9);
assert(stream.data == "11"); assert(stream.data == "11");
@ -3812,7 +3812,7 @@ unittest
r = std.string.format("%#X", 0xABCD); r = std.string.format("%#X", 0xABCD);
assert(r == "0XABCD"); assert(r == "0XABCD");
r = std.string.format("%#o", 012345); r = std.string.format("%#o", octal!12345);
assert(r == "012345"); assert(r == "012345");
r = std.string.format("%o", 9); r = std.string.format("%o", 9);
assert(r == "11"); assert(r == "11");

View file

@ -373,12 +373,12 @@ bool fromDecimalString(string s)
{ {
//Strip leading zeros //Strip leading zeros
int firstNonZero = 0; int firstNonZero = 0;
while ((firstNonZero < s.length - 1) && while ((firstNonZero < s.length) &&
(s[firstNonZero]=='0' || s[firstNonZero]=='_')) (s[firstNonZero]=='0' || s[firstNonZero]=='_'))
{ {
++firstNonZero; ++firstNonZero;
} }
if (firstNonZero == s.length - 1 && s.length > 1) if (firstNonZero == s.length && s.length >= 1)
{ {
data = ZERO; data = ZERO;
return true; return true;
@ -836,6 +836,12 @@ unittest
r.fromHexString("1_E1178E81_00000000"); r.fromHexString("1_E1178E81_00000000");
s = BigUint.pow(r, 15); // Regression test: this used to overflow array bounds s = BigUint.pow(r, 15); // Regression test: this used to overflow array bounds
r.fromDecimalString("000_000_00");
assert(r == 0);
r.fromDecimalString("0007");
assert(r == 7);
r.fromDecimalString("0");
assert(r == 0);
} }
// Radix conversion tests // Radix conversion tests
@ -1377,17 +1383,28 @@ size_t biguintToDecimal(char [] buff, BigDigit [] data)
* the highest index of data which was used. * the highest index of data which was used.
*/ */
int biguintFromDecimal(BigDigit [] data, string s) int biguintFromDecimal(BigDigit [] data, string s)
in
{
assert((data.length >= 2) || (data.length == 1 && s.length == 1));
}
body
{ {
// Convert to base 1e19 = 10_000_000_000_000_000_000. // Convert to base 1e19 = 10_000_000_000_000_000_000.
// (this is the largest power of 10 that will fit into a long). // (this is the largest power of 10 that will fit into a long).
// The length will be less than 1 + s.length/log2(10) = 1 + s.length/3.3219. // The length will be less than 1 + s.length/log2(10) = 1 + s.length/3.3219.
// 485 bits will only just fit into 146 decimal digits. // 485 bits will only just fit into 146 decimal digits.
uint lo = 0; // As we convert the string, we record the number of digits we've seen in base 19:
// hi is the number of digits/19, lo is the extra digits (0 to 18).
// TODO: This is inefficient for very large strings (it is O(n^^2)).
// We should take advantage of fast multiplication once the numbers exceed
// Karatsuba size.
uint lo = 0; // number of powers of digits, 0..18
uint x = 0; uint x = 0;
ulong y = 0; ulong y = 0;
uint hi = 0; uint hi = 0; // number of base 1e19 digits
data[0] = 0; // initially number is 0. data[0] = 0; // initially number is 0.
data[1] = 0; if (data.length > 1)
data[1] = 0;
for (int i= (s[0]=='-' || s[0]=='+')? 1 : 0; i<s.length; ++i) for (int i= (s[0]=='-' || s[0]=='+')? 1 : 0; i<s.length; ++i)
{ {
@ -1447,12 +1464,20 @@ int biguintFromDecimal(BigDigit [] data, string s)
for (int k=0; k<lo; ++k) y*=10; for (int k=0; k<lo; ++k) y*=10;
y+=x; y+=x;
} }
if (lo!=0) if (lo != 0)
{ {
if (hi==0) if (hi == 0)
{ {
*cast(ulong *)(&data[hi]) = y; if (data.length == 1)
hi=2; {
data[0] = cast(uint)(y & 0xFFFF_FFFF);
hi = 1;
}
else
{
*cast(ulong *)(&data[hi]) = y;
hi=2;
}
} }
else else
{ {
@ -1467,7 +1492,7 @@ int biguintFromDecimal(BigDigit [] data, string s)
--lo; --lo;
} }
uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF));
if (y>0xFFFF_FFFFL) if (y > 0xFFFF_FFFFL)
{ {
c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32));
} }
@ -1476,7 +1501,6 @@ int biguintFromDecimal(BigDigit [] data, string s)
data[hi]=c; data[hi]=c;
++hi; ++hi;
} }
// hi+=2;
} }
} }
while (hi>1 && data[hi-1]==0) while (hi>1 && data[hi-1]==0)

View file

@ -260,7 +260,7 @@ unittest {
for (int i=0; i<aa.length; ++i) aa[i] = 0x8765_4321 * (i+3); for (int i=0; i<aa.length; ++i) aa[i] = 0x8765_4321 * (i+3);
uint overflow = multibyteMul(aa, aa, 0x8EFD_FCFB, 0x33FF_7461); uint overflow = multibyteMul(aa, aa, 0x8EFD_FCFB, 0x33FF_7461);
uint r = multibyteDivAssign(aa, 0x8EFD_FCFB, overflow); uint r = multibyteDivAssign(aa, 0x8EFD_FCFB, overflow);
for (sizediff_t i=aa.length-1; i>=0; --i) { assert(aa[i] == 0x8765_4321 * (i+3)); } for (int i=0; i<aa.length; ++i) { assert(aa[i] == 0x8765_4321 * (i+3)); }
assert(r==0x33FF_7461); assert(r==0x33FF_7461);
} }

View file

@ -107,14 +107,14 @@ class MmFile
flags = MAP_SHARED; flags = MAP_SHARED;
prot = PROT_READ | PROT_WRITE; prot = PROT_READ | PROT_WRITE;
oflag = O_CREAT | O_RDWR | O_TRUNC; oflag = O_CREAT | O_RDWR | O_TRUNC;
fmode = 0660; fmode = octal!660;
break; break;
case Mode.ReadWrite: case Mode.ReadWrite:
flags = MAP_SHARED; flags = MAP_SHARED;
prot = PROT_READ | PROT_WRITE; prot = PROT_READ | PROT_WRITE;
oflag = O_CREAT | O_RDWR; oflag = O_CREAT | O_RDWR;
fmode = 0660; fmode = octal!660;
break; break;
case Mode.ReadCopyOnWrite: case Mode.ReadCopyOnWrite:
@ -322,14 +322,14 @@ class MmFile
flags = MAP_SHARED; flags = MAP_SHARED;
prot = PROT_READ | PROT_WRITE; prot = PROT_READ | PROT_WRITE;
oflag = O_CREAT | O_RDWR | O_TRUNC; oflag = O_CREAT | O_RDWR | O_TRUNC;
fmode = 0660; fmode = octal!660;
break; break;
case Mode.ReadWrite: case Mode.ReadWrite:
flags = MAP_SHARED; flags = MAP_SHARED;
prot = PROT_READ | PROT_WRITE; prot = PROT_READ | PROT_WRITE;
oflag = O_CREAT | O_RDWR; oflag = O_CREAT | O_RDWR;
fmode = 0660; fmode = octal!660;
break; break;
case Mode.ReadCopyOnWrite: case Mode.ReadCopyOnWrite:

View file

@ -793,7 +793,7 @@ class Stream : InputStream, OutputStream {
case 'o': { // octal case 'o': { // octal
while (isoctdigit(c) && width) { while (isoctdigit(c) && width) {
n = n * 010 + (c - '0'); n = n * 8 + (c - '0');
width--; width--;
c = getc(); c = getc();
count++; count++;
@ -1890,7 +1890,7 @@ class File: Stream {
} }
} }
version (Posix) { version (Posix) {
share = 0666; share = octal!666;
if (mode & FileMode.In) { if (mode & FileMode.In) {
access = O_RDONLY; access = O_RDONLY;
} }

View file

@ -92,7 +92,7 @@ test.obj : test.d
test.exe : test.obj phobos.lib test.exe : test.obj phobos.lib
$(DMD) test.obj -g -L/map $(DMD) test.obj -g -L/map
OBJS= Czlib.obj Dzlib.obj \ OBJS= Czlib.obj Dzlib.obj Ccurl.obj \
oldsyserror.obj \ oldsyserror.obj \
c_stdio.obj c_stdio.obj
@ -113,8 +113,8 @@ SRCS_1 = std\math.d std\stdio.d std\dateparse.d std\date.d std\datetime.d \
std\intrinsic.d \ std\intrinsic.d \
std\process.d \ std\process.d \
std\system.d \ std\system.d \
std\encoding.d std\encoding.d
SRCS_2 = std\variant.d \ SRCS_2 = std\variant.d \
std\stream.d std\socket.d std\socketstream.d \ std\stream.d std\socket.d std\socketstream.d \
std\perf.d std\container.d std\conv.d \ std\perf.d std\container.d std\conv.d \
@ -287,11 +287,11 @@ SRC_STD_C_FREEBSD= std\c\freebsd\socket.d
SRC_STD_INTERNAL_MATH= std\internal\math\biguintcore.d \ SRC_STD_INTERNAL_MATH= std\internal\math\biguintcore.d \
std\internal\math\biguintnoasm.d std\internal\math\biguintx86.d \ std\internal\math\biguintnoasm.d std\internal\math\biguintx86.d \
std\internal\math\gammafunction.d std\internal\math\errorfunction.d std\internal\math\gammafunction.d std\internal\math\errorfunction.d
SRC_ETC= SRC_ETC=
SRC_ETC_C= etc\c\zlib.d SRC_ETC_C= etc\c\zlib.d etc\c\curl.d
SRC_ZLIB= \ SRC_ZLIB= \
etc\c\zlib\crc32.h \ etc\c\zlib\crc32.h \
@ -547,7 +547,7 @@ biguintnoasm.obj : std\internal\math\biguintnoasm.d
biguintx86.obj : std\internal\math\biguintx86.d biguintx86.obj : std\internal\math\biguintx86.d
$(DMD) -c $(DFLAGS) std\internal\math\biguintx86.d $(DMD) -c $(DFLAGS) std\internal\math\biguintx86.d
gammafunction.obj : std\internal\math\gammafunction.d gammafunction.obj : std\internal\math\gammafunction.d
$(DMD) -c $(DFLAGS) std\internal\math\gammafunction.d $(DMD) -c $(DFLAGS) std\internal\math\gammafunction.d
@ -583,6 +583,9 @@ c_stdio.obj : std\c\stdio.d
Czlib.obj : etc\c\zlib.d Czlib.obj : etc\c\zlib.d
$(DMD) -c $(DFLAGS) etc\c\zlib.d -ofCzlib.obj $(DMD) -c $(DFLAGS) etc\c\zlib.d -ofCzlib.obj
Ccurl.obj : etc\c\curl.d
$(DMD) -c $(DFLAGS) etc\c\curl.d -ofCcurl.obj
### std\c\windows ### std\c\windows
com.obj : std\c\windows\com.d com.obj : std\c\windows\com.d
@ -928,8 +931,8 @@ install:
$(CP) $(DOCS) $(DIR)\html\d\phobos $(CP) $(DOCS) $(DIR)\html\d\phobos
svn: svn:
$(CP) win32.mak posix.mak $(STDDOC) $(SVN)\ $(CP) win32.mak posix.mak $(STDDOC) $(SVN)\
$(CP) $(SRC) $(SVN)\ $(CP) $(SRC) $(SVN)\
$(CP) $(SRC_STD) $(SVN)\std $(CP) $(SRC_STD) $(SVN)\std
$(CP) $(SRC_STD_C) $(SVN)\std\c $(CP) $(SRC_STD_C) $(SVN)\std\c
$(CP) $(SRC_STD_WIN) $(SVN)\std\windows $(CP) $(SRC_STD_WIN) $(SVN)\std\windows