One pass through std.range and friends

* Made emplace faster and replaced calls to it to also make them faster.

* Replaced phobos.d in posix.mak with index.d.

* Added version=StdDdoc to documentation build in posix.mak, and replaced uses of D_Ddoc with it.

* Improved documentation target in posix.mak (target dir automatically created).

* Added nice documentation table and cheat sheet at the top of std.algorithm.

* Replaced a few helper structs in std.range and std.algorithm with local structs, which simplify matters a fair amount.

* Added more constraints to functions in std.algorithm (still work in progress).

* Improved error message in std.algorithm.sort in case of failure to sort.

* std.random.dice(1, 10) now works (no need for array notation std.random.dice([1, 10])).

* Fixed documentation bugs and insufficiencies in std.range (still more to do).

* Improved speed of walkLength.

* Simplified retro.

* Simplified and optimized stride. Also folded stride(stride(r, a), b) into stride(r, a * b).

* Added roundRobin to std.range, which as a perk simplified radial.

* Added takeOne and takeNone to std.range.

* Added unsigned to std.traits.
This commit is contained in:
Andrei Alexandrescu 2011-02-26 15:15:36 -06:00
parent 69d8b2e514
commit 1083bd4e7b
13 changed files with 2861 additions and 2420 deletions

View file

@ -53,9 +53,9 @@ ROOT = $(ROOT_OF_THEM_ALL)/$(OS)/$(BUILD)/$(MODEL)
DOCSRC = ../d-programming-language.org DOCSRC = ../d-programming-language.org
WEBSITE_DIR = ../web WEBSITE_DIR = ../web
DOC_OUTPUT_DIR = $(WEBSITE_DIR)/phobos-prerelease DOC_OUTPUT_DIR = $(WEBSITE_DIR)/phobos-prerelease
SRC_DOCUMENTABLES = phobos.d $(addsuffix .d,$(STD_MODULES)) SRC_DOCUMENTABLES = index.d $(addsuffix .d,$(STD_MODULES))
STDDOC = $(DOCSRC)/std.ddoc STDDOC = $(DOCSRC)/std.ddoc
DDOCFLAGS=-m$(MODEL) -d -c -o- $(STDDOC) -I$(DRUNTIME_PATH)/import $(DMDEXTRAFLAGS) DDOCFLAGS=-m$(MODEL) -d -c -o- -version=StdDdoc $(STDDOC) -I$(DRUNTIME_PATH)/import $(DMDEXTRAFLAGS)
# Variable defined in an OS-dependent manner (see below) # Variable defined in an OS-dependent manner (see below)
CC = CC =
@ -248,7 +248,7 @@ DISABLED_TESTS += std/math
DISABLED_TESTS += std/random DISABLED_TESTS += std/random
DISABLED_TESTS += std/internal/math/biguintnoasm DISABLED_TESTS += std/internal/math/biguintnoasm
$(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : $(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) :
@echo Testing $@ - disabled @echo Testing $@ - disabled
endif endif
@ -288,8 +288,8 @@ $(DRUNTIME) :
########################################################### ###########################################################
# html documentation # html documentation
$(DOC_OUTPUT_DIR)/%.html : %.d $(STDDOC) $(DOC_OUTPUT_DIR)/. :
$(DDOC) $(DDOCFLAGS) -Df$@ $< mkdir -p $@
$(DOC_OUTPUT_DIR)/std_%.html : std/%.d $(STDDOC) $(DOC_OUTPUT_DIR)/std_%.html : std/%.d $(STDDOC)
$(DDOC) $(DDOCFLAGS) -Df$@ $< $(DDOC) $(DDOCFLAGS) -Df$@ $<
@ -300,7 +300,10 @@ $(DOC_OUTPUT_DIR)/std_c_%.html : std/c/%.d $(STDDOC)
$(DOC_OUTPUT_DIR)/std_c_linux_%.html : std/c/linux/%.d $(STDDOC) $(DOC_OUTPUT_DIR)/std_c_linux_%.html : std/c/linux/%.d $(STDDOC)
$(DDOC) $(DDOCFLAGS) -Df$@ $< $(DDOC) $(DDOCFLAGS) -Df$@ $<
html : $(addprefix $(DOC_OUTPUT_DIR)/, $(subst /,_,$(subst .d,.html, \ $(DOC_OUTPUT_DIR)/%.html : %.d $(STDDOC)
$(DDOC) $(DDOCFLAGS) -Df$@ $<
html : $(DOC_OUTPUT_DIR)/. $(addprefix $(DOC_OUTPUT_DIR)/, $(subst /,_,$(subst .d,.html, \
$(SRC_DOCUMENTABLES)))) $(STYLECSS_TGT) $(SRC_DOCUMENTABLES)))) $(STYLECSS_TGT)
# @$(MAKE) -f $(DOCSRC)/linux.mak -C $(DOCSRC) --no-print-directory # @$(MAKE) -f $(DOCSRC)/linux.mak -C $(DOCSRC) --no-print-directory

File diff suppressed because it is too large Load diff

View file

@ -54,8 +54,7 @@ if (isIterable!Range && !isNarrowString!Range)
static if (is(typeof(e.opAssign(e)))) static if (is(typeof(e.opAssign(e))))
{ {
// this should be in-place construction // this should be in-place construction
auto voidArr = (cast(void*) (result.ptr + i))[0..E.sizeof]; emplace!E(result.ptr + i, e);
emplace!E(voidArr, e);
} }
else else
{ {

View file

@ -7,7 +7,6 @@ Source: $(PHOBOSSRC std/_container.d)
Macros: Macros:
WIKI = Phobos/StdContainer WIKI = Phobos/StdContainer
TEXTWITHCOMMAS = $0 TEXTWITHCOMMAS = $0
LEADINGROW = <tr style=leadingrow bgcolor=#E4E9EF><td colspan=3><b><em>$0</em></b></td></tr>
Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code
copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders.
@ -1234,7 +1233,7 @@ $(D r) and $(D m) is the length of $(D stuff).
*/ */
size_t insertAfter(Stuff)(Take!Range r, Stuff stuff) size_t insertAfter(Stuff)(Take!Range r, Stuff stuff)
{ {
auto orig = r.original; auto orig = r.source;
if (!orig._head) if (!orig._head)
{ {
// Inserting after a null range counts as insertion to the // Inserting after a null range counts as insertion to the
@ -1287,7 +1286,7 @@ Complexity: $(BIGOH n)
*/ */
Range linearRemove(Take!Range r) Range linearRemove(Take!Range r)
{ {
auto orig = r.original; auto orig = r.source;
// We have something to remove here // We have something to remove here
if (orig._head == _root) if (orig._head == _root)
{ {
@ -1571,9 +1570,7 @@ struct Array(T) if (!is(T : const(bool)))
reserve(1 + capacity * 3 / 2); reserve(1 + capacity * 3 / 2);
} }
assert(capacity > length && _payload.ptr); assert(capacity > length && _payload.ptr);
emplace!T((cast(void*) (_payload.ptr + _payload.length)) emplace(_payload.ptr + _payload.length, stuff);
[0 .. T.sizeof],
stuff);
_payload = _payload.ptr[0 .. _payload.length + 1]; _payload = _payload.ptr[0 .. _payload.length + 1];
return 1; return 1;
} }
@ -1605,17 +1602,17 @@ struct Array(T) if (!is(T : const(bool)))
this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
{ {
auto p = malloc(T.sizeof * values.length); auto p = cast(T*) malloc(T.sizeof * values.length);
if (hasIndirections!T && p) if (hasIndirections!T && p)
{ {
GC.addRange(p, T.sizeof * values.length); GC.addRange(p, T.sizeof * values.length);
} }
foreach (i, e; values) foreach (i, e; values)
{ {
emplace!T(p[i * T.sizeof .. (i + 1) * T.sizeof], e); emplace(p + i, e);
assert((cast(T*) p)[i] == e); assert(p[i] == e);
} }
_data.RefCounted.initialize((cast(T*) p)[0 .. values.length]); _data.RefCounted.initialize(p[0 .. values.length]);
} }
/** /**
@ -2089,8 +2086,7 @@ Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff)
memmove(_data._payload.ptr + r._a + 1, memmove(_data._payload.ptr + r._a + 1,
_data._payload.ptr + r._a, _data._payload.ptr + r._a,
T.sizeof * (length - r._a)); T.sizeof * (length - r._a));
emplace!T((cast(void*) (_data._payload.ptr + r._a))[0 .. T.sizeof], emplace(_data._payload.ptr + r._a, stuff);
stuff);
_data._payload = _data._payload.ptr[0 .. _data._payload.length + 1]; _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1];
return 1; return 1;
} }
@ -2114,7 +2110,7 @@ Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff)
foreach (p; _data._payload.ptr + r._a .. foreach (p; _data._payload.ptr + r._a ..
_data._payload.ptr + r._a + extra) _data._payload.ptr + r._a + extra)
{ {
emplace!T((cast(void*) p)[0 .. T.sizeof], stuff.front); emplace(p, stuff.front);
stuff.popFront(); stuff.popFront();
} }
_data._payload = _data._payload =

View file

@ -3048,7 +3048,6 @@ version (none)
assert(to!string(cr) == to!string(creal.nan)); assert(to!string(cr) == to!string(creal.nan));
assert(feq(cr, creal.nan)); assert(feq(cr, creal.nan));
} }
} }
/* ************************************************************** /* **************************************************************
@ -3956,7 +3955,8 @@ template octal(alias s) if (isIntegral!(typeof(s))) {
unittest unittest
{ {
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__,
" succeeded.");
// ensure that you get the right types, even with embedded underscores // ensure that you get the right types, even with embedded underscores
auto w = octal!"100_000_000_000"; auto w = octal!"100_000_000_000";
static assert(!is(typeof(w) == int)); static assert(!is(typeof(w) == int));
@ -4022,114 +4022,86 @@ T toImpl(T, S)(S src) if (is(T == struct) && is(typeof(T(src))))
// Bugzilla 3961 // Bugzilla 3961
unittest unittest
{ {
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__,
" succeeded.");
struct Int { int x; } struct Int { int x; }
Int i = to!Int(1); Int i = to!Int(1);
} }
// emplace // emplace
/** /**
Given a raw memory area $(D chunk), constructs an object of non-$(D Given a pointer $(D chunk) to uninitialized memory (but already typed
class) type $(D T) at that address. The constructor is passed the as $(D T)), constructs an object of non-$(D class) type $(D T) at that
arguments $(D Args). The $(D chunk) must be as least as large as $(D address.
T) needs and should have an alignment multiple of $(D T)'s alignment.
This function can be $(D @trusted) if the corresponding constructor of This function can be $(D @trusted) if the corresponding constructor of
$(D T) is $(D @safe). $(D T) is $(D @safe).
Returns: A pointer to the newly constructed object. Returns: A pointer to the newly constructed object (which is the same
as $(D chunk)).
*/ */
T* emplace(T, Args...)(void[] chunk, Args args) if (!is(T == class)) T* emplace(T)(T* chunk)
if (!is(T == class))
{ {
enforce(chunk.length >= T.sizeof, auto result = cast(typeof(return)) chunk;
new ConvException("emplace: target size too small")); static T i;
auto a = cast(size_t) chunk.ptr; memcpy(result, &i, T.sizeof);
version (OSX) // for some reason, breaks on other platforms return result;
enforce(a % T.alignof == 0, new ConvException("misalignment")); }
auto result = cast(typeof(return)) chunk.ptr;
/**
Given a pointer $(D chunk) to uninitialized memory (but already typed
as a non-class type $(D T)), constructs an object of type $(D T) at
that address from arguments $(D args).
This function can be $(D @trusted) if the corresponding constructor of
$(D T) is $(D @safe).
Returns: A pointer to the newly constructed object (which is the same
as $(D chunk)).
*/
T* emplace(T, Args...)(T* chunk, Args args)
if (!is(T == class) && !is(T == struct) && Args.length == 1)
{
*chunk = args[0];
return chunk;
}
// Specialization for struct
T* emplace(T, Args...)(T* chunk, Args args)
if (is(T == struct))
{
auto result = cast(typeof(return)) chunk;
void initialize() void initialize()
{ {
static T i; static T i;
memcpy(chunk.ptr, &i, T.sizeof); memcpy(chunk, &i, T.sizeof);
} }
static if (Args.length == 0) static if (is(typeof(result.__ctor(args))))
{ {
// Just initialize the thing // T defines a genuine constructor accepting args
// Go the classic route: write .init first, then call ctor
initialize(); initialize();
result.__ctor(args);
} }
else static if (is(T == struct)) else static if (is(typeof(T(args))))
{ {
static if (is(typeof(result.__ctor(args)))) // Struct without constructor that has one matching field for
{ // each argument
// T defines a genuine constructor accepting args *result = T(args);
// Go the classic route: write .init first, then call ctor
initialize();
result.__ctor(args);
}
else static if (is(typeof(T(args))))
{
// Struct without constructor that has one matching field for
// each argument
initialize();
*result = T(args);
}
else static if (Args.length == 1 && is(Args[0] : T))
{
initialize();
*result = args[0];
}
} }
else static if (Args.length == 1 && is(Args[0] : T)) else //static if (Args.length == 1 && is(Args[0] : T))
{ {
// Primitive type. Assignment is fine for initialization. static assert(Args.length == 1);
//static assert(0, T.stringof ~ " " ~ Args.stringof);
// initialize();
*result = args[0]; *result = args[0];
} }
else
{
static assert(false, "Don't know how to initialize an object of type "
~ T.stringof ~ " with arguments " ~ Args.stringof);
}
return result; return result;
} }
unittest
{
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
int a;
int b = 42;
assert(*emplace!int((cast(void*) &a)[0 .. int.sizeof], b) == 42);
struct S
{
double x = 5, y = 6;
this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; }
}
auto s1 = new void[S.sizeof];
auto s2 = S(42, 43);
assert(*emplace!S(s1, s2) == s2);
assert(*emplace!S(s1, 44, 45) == S(44, 45));
}
// emplace
/**
Similar to $(D emplace) above, except it receives a pointer to an
uninitialized object of type $(D T). This overload is useful for
e.g. initializing member variables or stack variables defined with $(D
T variable = void).
Returns: A pointer to the newly constructed object.
*/
T* emplace(T, Args...)(T* chunk, Args args) if (!is(T == class))
{
// Since we're treating the memory pointed to by chunk as a raw memory
// block, we need to cast away any qualifiers.
return cast(T*) emplace!(Unqual!T)((cast(void*) chunk)[0 .. T.sizeof], args);
}
// emplace
/** /**
Given a raw memory area $(D chunk), constructs an object of $(D class) Given a raw memory area $(D chunk), constructs an object of $(D class)
type $(D T) at that address. The constructor is passed the arguments type $(D T) at that address. The constructor is passed the arguments
@ -4170,6 +4142,60 @@ T emplace(T, Args...)(void[] chunk, Args args) if (is(T == class))
return result; return result;
} }
/**
Given a raw memory area $(D chunk), constructs an object of non-$(D
class) type $(D T) at that address. The constructor is passed the
arguments $(D args), if any. The $(D chunk) must be as least as large
as $(D T) needs and should have an alignment multiple of $(D T)'s
alignment.
This function can be $(D @trusted) if the corresponding constructor of
$(D T) is $(D @safe).
Returns: A pointer to the newly constructed object.
*/
T* emplace(T, Args...)(void[] chunk, Args args)
if (!is(T == class))
{
enforce(chunk.length >= T.sizeof,
new ConvException("emplace: chunk size too small"));
auto a = cast(size_t) chunk.ptr;
enforce(a % T.alignof == 0, text(a, " vs. ", T.alignof));
auto result = cast(typeof(return)) chunk.ptr;
return emplace(result, args);
}
unittest
{
struct S { int a, b; }
auto p = new void[S.sizeof];
S s;
s.a = 42;
s.b = 43;
auto s1 = emplace!S(p, s);
assert(s1.a == 42 && s1.b == 43);
}
unittest
{
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__,
" succeeded.");
int a;
int b = 42;
assert(*emplace!int(&a, b) == 42);
struct S
{
double x = 5, y = 6;
this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; }
}
auto s1 = new void[S.sizeof];
auto s2 = S(42, 43);
assert(*emplace!S(cast(S*) s1.ptr, s2) == s2);
assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45));
}
unittest unittest
{ {
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
@ -4200,7 +4226,6 @@ unittest
} }
Foo foo; Foo foo;
auto voidArr = (cast(void*) &foo)[0..Foo.sizeof]; emplace!Foo(&foo, 2U);
emplace!Foo(voidArr, 2U);
assert(foo.num == 2); assert(foo.num == 2);
} }

View file

@ -28496,7 +28496,7 @@ public:
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
The name of the time zone per the TZ Database. This is the name used to The name of the time zone per the TZ Database. This is the name used to
@ -30587,7 +30587,7 @@ private:
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
@ -31119,7 +31119,7 @@ else version(Windows)
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
$(BLUE This function is Posix-Only.) $(BLUE This function is Posix-Only.)
@ -32189,7 +32189,7 @@ unittest
} }
version(D_Ddoc) version(StdDdoc)
{ {
version(Windows) {} version(Windows) {}
else else
@ -32982,76 +32982,61 @@ unittest
} }
} }
/++
Function for starting to a stop watch time when the function is called
and stopping it when its return value goes out of scope and is
destroyed.
version(D_Ddoc) When the value that is returned by this function is destroyed, $(D
{ func) will run. $(D func) is a unary function that takes a $(D
/++ TickDuration).
Function for starting to a stop watch time when the function is called
and stopping it when its return value goes out of scope and is destroyed.
When the value that is returned by this function is destroyed, Examples:
$(D func) will run. $(D func) is a unary function that takes a
$(D TickDuration).
Examples:
-------------------- --------------------
writeln("benchmark start!"); writeln("benchmark start!");
{ {
auto mt = measureTime!((a){assert(a.seconds);}); auto mt = measureTime!((a){assert(a.seconds);});
doSomething(); doSomething();
} }
writeln("benchmark end!"); writeln("benchmark end!");
-------------------- --------------------
+/ +/
auto measureTime(alias func)(); @safe auto measureTime(alias func)()
} if(isSafe!func)
else
{ {
@safe struct Result
{ {
auto measureTime(alias func)() private StopWatch sw = void;
if(isSafe!func) this(StopWatch.AutoStart as)
{ {
struct TMP sw = StopWatch(as);
{ }
private StopWatch sw = void; ~this()
this(StopWatch.AutoStart as) {
{ unaryFun!(func)(sw.peek());
sw = StopWatch(as);
}
~this()
{
unaryFun!(func)(sw.peek());
}
}
return TMP(autoStart);
}
}
@system
{
auto measureTime(alias func)()
if (!isSafe!func)
{
struct TMP
{
private StopWatch sw = void;
this(AutoStart as)
{
sw = StopWatch(as);
}
~this()
{
unaryFun!(func)(sw.peek());
}
}
return TMP(autoStart);
} }
} }
return Result(autoStart);
} }
@system @system auto measureTime(alias func)() if (!isSafe!func)
unittest {
struct TMP
{
private StopWatch sw = void;
this(AutoStart as)
{
sw = StopWatch(as);
}
~this()
{
unaryFun!(func)(sw.peek());
}
}
return TMP(autoStart);
}
@system unittest
{ {
version(testStdDateTime) version(testStdDateTime)
{ {

View file

@ -601,7 +601,7 @@ unittest
* $(RED Scheduled for deprecation. Please use getTimesWin (for Windows) * $(RED Scheduled for deprecation. Please use getTimesWin (for Windows)
* or getTimesPosix (for Posix) instead.) * or getTimesPosix (for Posix) instead.)
*/ */
version(D_Ddoc) version(StdDdoc)
{ {
void getTimes(in char[] name, void getTimes(in char[] name,
out d_time ftc, out d_time ftc,
@ -668,7 +668,7 @@ else
static assert(0, "Unsupported/Unknown OS"); static assert(0, "Unsupported/Unknown OS");
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
$(BLUE This function is Windows-Only.) $(BLUE This function is Windows-Only.)
@ -877,7 +877,7 @@ else
static assert(0, "Unsupported/Unknown OS"); static assert(0, "Unsupported/Unknown OS");
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
$(RED Scheduled for deprecation. Please use $(RED Scheduled for deprecation. Please use
@ -911,7 +911,7 @@ else
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
$(RED Scheduled for deprecation. Please use timeLastModified instead.) $(RED Scheduled for deprecation. Please use timeLastModified instead.)
@ -1138,7 +1138,7 @@ uint getAttributes(in char[] name)
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
If the given file is a symbolic link, then this returns the attributes of the If the given file is a symbolic link, then this returns the attributes of the
@ -1724,7 +1724,7 @@ unittest
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
Info on a file, similar to what you'd get from stat on a Posix system. Info on a file, similar to what you'd get from stat on a Posix system.
@ -2497,7 +2497,7 @@ version(Posix) void copy(in char[] from, in char[] to)
cenforce(utime(toz, &utim) != -1, from); cenforce(utime(toz, &utim) != -1, from);
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
$(RED Scheduled for deprecation. Please use the version which takes $(RED Scheduled for deprecation. Please use the version which takes
@ -2553,7 +2553,7 @@ else
} }
version(D_Ddoc) version(StdDdoc)
{ {
/++ /++
Set access/modified times of file $(D name). Set access/modified times of file $(D name).

View file

@ -498,7 +498,7 @@ struct FormatSpec(Char)
$(D ubyte.max). ($(D 0) means not used). $(D ubyte.max). ($(D 0) means not used).
*/ */
ubyte index; ubyte index;
version(D_Ddoc) { version(StdDdoc) {
/** /**
The format specifier contained a $(D '-') ($(D printf) The format specifier contained a $(D '-') ($(D printf)
compatibility). compatibility).

View file

@ -383,8 +383,7 @@ template adjoin(F...) if (F.length)
Tuple!(Head, typeof(.adjoin!(F[1..$])(a)).Types) result = void; Tuple!(Head, typeof(.adjoin!(F[1..$])(a)).Types) result = void;
foreach (i, Unused; result.Types) foreach (i, Unused; result.Types)
{ {
auto store = (cast(void*) &result[i])[0 .. result[i].sizeof]; emplace(&result[i], F[i](a));
emplace!(typeof(result[i]))(store, F[i](a));
} }
return result; return result;
} }

View file

@ -878,7 +878,7 @@ auto a = uniform(0, 1024, gen);
auto a = uniform(0.0f, 1.0f, gen); auto a = uniform(0.0f, 1.0f, gen);
---- ----
*/ */
version(D_Ddoc) version(StdDdoc)
CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)", CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)",
T1, T2, UniformRandomNumberGenerator) T1, T2, UniformRandomNumberGenerator)
(T1 a, T2 b, ref UniformRandomNumberGenerator urng); (T1 a, T2 b, ref UniformRandomNumberGenerator urng);
@ -964,7 +964,7 @@ if (is(CommonType!(T1, UniformRandomNumberGenerator) == void) &&
/** /**
As above, but uses the default generator $(D rndGen). As above, but uses the default generator $(D rndGen).
*/ */
version(D_Ddoc) version(StdDdoc)
CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)", T1, T2) CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)", T1, T2)
(T1 a, T2 b) if (!is(CommonType!(T1, T2) == void)); (T1 a, T2 b) if (!is(CommonType!(T1, T2) == void));
else else
@ -1082,34 +1082,39 @@ auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 30% of the time,
// and 2 10% of the time // and 2 10% of the time
---- ----
*/ */
size_t dice(R, Num)(ref R rnd, Num[] proportions...) size_t dice(Rng, Num)(ref Rng rnd, Num[] proportions...)
if(isNumeric!Num) { if (isNumeric!Num && isForwardRange!Rng)
{
return diceImpl(rnd, proportions); return diceImpl(rnd, proportions);
} }
/// Ditto /// Ditto
size_t dice(R, Range)(ref R rnd, Range proportions) size_t dice(R, Range)(ref R rnd, Range proportions)
if(isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) { if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range)
{
return diceImpl(rnd, proportions); return diceImpl(rnd, proportions);
} }
/// Ditto /// Ditto
size_t dice(Num)(Num[] proportions...) size_t dice(Range)(Range proportions)
if(isNumeric!Num) { if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range)
{
return diceImpl(rndGen(), proportions); return diceImpl(rndGen(), proportions);
} }
/// Ditto /// Ditto
size_t dice(Range)(Range proportions) size_t dice(Num)(Num[] proportions...)
if(isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) { if (isNumeric!Num)
{
return diceImpl(rndGen(), proportions); return diceImpl(rndGen(), proportions);
} }
private size_t diceImpl(R, Range)(ref R rnd, Range proportions) private size_t diceImpl(Rng, Range)(ref Rng rng, Range proportions)
if(isForwardRange!Range && isNumeric!(ElementType!Range)) { if (isForwardRange!Range && isNumeric!(ElementType!Range) && isForwardRange!Rng)
immutable sum = reduce!("(assert(b >= 0), a + b)")(0.0, proportions.save); {
double sum = reduce!("(assert(b >= 0), a + b)")(0.0, proportions.save);
enforce(sum > 0, "Proportions in a dice cannot sum to zero"); enforce(sum > 0, "Proportions in a dice cannot sum to zero");
immutable point = uniform(0.0, sum, rnd); immutable point = uniform(0.0, sum, rng);
assert(point < sum); assert(point < sum);
auto mass = 0.0; auto mass = 0.0;
@ -1123,8 +1128,6 @@ if(isForwardRange!Range && isNumeric!(ElementType!Range)) {
assert(false); assert(false);
} }
unittest { unittest {
auto rnd = Random(unpredictableSeed); auto rnd = Random(unpredictableSeed);
auto i = dice(rnd, 0.0, 100.0); auto i = dice(rnd, 0.0, 100.0);
@ -1132,13 +1135,7 @@ unittest {
i = dice(rnd, 100.0, 0.0); i = dice(rnd, 100.0, 0.0);
assert(i == 0); assert(i == 0);
i = dice([100U, 0U]); i = dice(100U, 0U);
assert(i == 0);
i = dice(filter!"a >= 0"([100U, 0U]));
assert(i == 0);
i = dice(rnd, filter!"a >= 0"([100U, 0U]));
assert(i == 0); assert(i == 0);
} }

File diff suppressed because it is too large Load diff

View file

@ -3376,6 +3376,29 @@ unittest
assert(is(S2 == immutable(int)), S2.stringof); assert(is(S2 == immutable(int)), S2.stringof);
} }
/**
* Returns the corresponding unsigned value for $(D x), e.g. if $(D x)
* has type $(D int), returns $(D cast(uint) x). The advantage
* compared to the cast is that you do not need to rewrite the cast if
* $(D x) later changes type to e.g. $(D long).
*/
auto unsigned(T)(T x) if (isIntegral!T)
{
static if (is(Unqual!T == byte)) return cast(ubyte) x;
else static if (is(Unqual!T == short)) return cast(ushort) x;
else static if (is(Unqual!T == int)) return cast(uint) x;
else static if (is(Unqual!T == long)) return cast(ulong) x;
else
{
static assert(T.min == 0, "Bug in either unsigned or isIntegral");
return x;
}
}
unittest
{
static assert(is(typeof(unsigned(1 + 1)) == uint));
}
/** /**
Returns the most negative value of the numeric type T. Returns the most negative value of the numeric type T.

View file

@ -2286,7 +2286,7 @@ if (!is(T == class))
{ {
GC.addRange(p.ptr, sz); GC.addRange(p.ptr, sz);
} }
emplace!T(p[0 .. T.sizeof], args); emplace(cast(T*) p.ptr, args);
_store = cast(typeof(_store)) p.ptr; _store = cast(typeof(_store)) p.ptr;
_store._count = 1; _store._count = 1;
debug(RefCounted) if (debugging) writeln(typeof(this).stringof, debug(RefCounted) if (debugging) writeln(typeof(this).stringof,