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
WEBSITE_DIR = ../web
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
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)
CC =
@ -288,8 +288,8 @@ $(DRUNTIME) :
###########################################################
# html documentation
$(DOC_OUTPUT_DIR)/%.html : %.d $(STDDOC)
$(DDOC) $(DDOCFLAGS) -Df$@ $<
$(DOC_OUTPUT_DIR)/. :
mkdir -p $@
$(DOC_OUTPUT_DIR)/std_%.html : std/%.d $(STDDOC)
$(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)
$(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)
# @$(MAKE) -f $(DOCSRC)/linux.mak -C $(DOCSRC) --no-print-directory

View file

@ -1,14 +1,50 @@
// Written in the D programming language.
/**
<script>inhibitQuickIndex = 1</script>
<script src="/cutting-edge/js/hyphenate.js" type="text/javascript"></script>
$(BOOKTABLE ,
$(TR $(TH Csategory) $(TH Functions))
$(TR $(TDNW Searching) $(TD $(MYREF balancedParens) $(MYREF
boyerMooreFinder) $(MYREF canFind) $(MYREF count) $(MYREF countUntil)
$(MYREF endsWith) $(MYREF find) $(MYREF findAdjacent) $(MYREF
findAmong) $(MYREF findSkip) $(MYREF findSplit) $(MYREF
findSplitAfter) $(MYREF findSplitBefore) $(MYREF indexOf) $(MYREF
minCount) $(MYREF minPos) $(MYREF mismatch) $(MYREF skipOver) $(MYREF
startsWith) $(MYREF until) ))
$(TR $(TDNW Comparison) $(TD $(MYREF cmp) $(MYREF equal) $(MYREF
levenshteinDistance) $(MYREF levenshteinDistanceAndPath) $(MYREF max)
$(MYREF min) $(MYREF mismatch)))
$(TR $(TDNW Iteration) $(TD $(MYREF filter) $(MYREF filterBidirectional)
$(MYREF group) $(MYREF joiner) $(MYREF map) $(MYREF reduce) $(MYREF
splitter) $(MYREF uniq) ))
$(TR $(TDNW Sorting) $(TD $(MYREF completeSort) $(MYREF isPartitioned)
$(MYREF isSorted) $(MYREF makeIndex) $(MYREF partialSort) $(MYREF
partition) $(MYREF schwartzSort) $(MYREF sort) $(MYREF topN) $(MYREF
topNCopy)))
$(TR $(TDNW Set&nbsp;operations) $(TD $(MYREF
largestPartialIntersection) $(MYREF largestPartialIntersectionWeighted)
$(MYREF nWayUnion) $(MYREF setDifference) $(MYREF setIntersection) $(MYREF
setSymmetricDifference) $(MYREF setUnion) ))
$(TR $(TDNW Mutation) $(TD $(MYREF bringToFront) $(MYREF copy) $(MYREF
fill) $(MYREF initializeAll) $(MYREF move) $(MYREF moveAll) $(MYREF
moveSome) $(MYREF remove) $(MYREF reverse) $(MYREF swap) $(MYREF
swapRanges) $(MYREF uninitializedFill) ))
)
Implements algorithms oriented mainly towards processing of
sequences. Some functions are semantic equivalents or supersets of
those found in the $(D $(LESS)_algorithm$(GREATER)) header in $(WEB
sgi.com/tech/stl/, Alexander Stepanov's Standard Template Library) for
C++.
Note:
Many functions in this module are parameterized with a function or a
$(GLOSSARY predicate). The predicate may be passed either as a
function name, a delegate name, a $(GLOSSARY functor) name, or a
@ -34,9 +70,239 @@ sort!("a > b")(a); // predicate as string
sort(a); // no predicate, "a < b" is implicit
----
Source: $(PHOBOSSRC std/_algorithm.d)
$(BOOKTABLE Cheat Sheet,
$(TR $(TH Function Name) $(TH Description))
$(LEADINGROW Searching)
$(TR $(TDNW $(MYREF balancedParens)) $(TD $(D
balancedParens("((1 + 1) / 2)")) returns $(D true) because the string
has balanced parentheses.))
$(TR $(TDNW $(MYREF boyerMooreFinder)) $(TD $(D find("hello
world", boyerMooreFinder("or"))) returns $(D "orld") using the $(LUCKY
Boyer-Moore _algorithm).))
$(TR $(TDNW $(LREF canFind)) $(TD $(D find("hello world",
"or")) returns $(D true).))
$(TR $(TDNW $(LREF count)) $(TD Counts elements that are equal
to a specified value or satisfy a predicate. $(D count([1, 2, 1], 1))
returns $(D 2) and $(D count!"a < 0"([1, -3, 0])) returns $(D 1).))
$(TR $(TDNW $(LREF countUntil)) $(TD $(D countUntil(a, b))
returns the number of steps taken in $(D a) to reach $(D b); for
example, $(D countUntil("hello!", "o")) returns $(D 4).))
$(TR $(TDNW $(LREF endsWith)) $(TD $(D endsWith("rocks", "ks"))
returns $(D true).))
$(TR $(TD $(MYREF find)) $(TD $(D find("hello world",
"or")) returns $(D "orld") using linear search.))
$(TR $(TDNW $(LREF findAdjacent)) $(TD $(D findAdjacent([1, 2,
3, 3, 4])) returns the subrange starting with two equal adjacent
elements, i.e. $(D [3, 3, 4]).))
$(TR $(TDNW $(LREF findAmong)) $(TD $(D findAmong("abcd",
"qcx")) returns $(D "cd") because $(D 'c') is among $(D "qcx").))
$(TR $(TDNW $(LREF findSkip)) $(TD If $(D a = "abcde"), then
$(D findSkip(a, "x")) returns $(D false) and leaves $(D a) unchanged,
whereas $(D findSkip(a, 'c')) advances $(D a) to $(D "cde") and
returns $(D true).))
$(TR $(TDNW $(LREF findSplit)) $(TD $(D findSplit("abcdefg",
"de")) returns the three ranges $(D "abc"), $(D "de"), and $(D
"fg").))
$(TR $(TDNW $(LREF findSplitAfter)) $(TD $(D
findSplitAfter("abcdefg", "de")) returns the two ranges $(D "abcde")
and $(D "fg").))
$(TR $(TDNW $(LREF findSplitBefore)) $(TD $(D
findSplitBefore("abcdefg", "de")) returns the two ranges $(D "abc") and
$(D "defg").))
$(TR $(TDNW $(LREF minCount)) $(TD $(D minCount([2, 1, 1, 4,
1])) returns $(D tuple(1, 3)).))
$(TR $(TDNW $(LREF minPos)) $(TD $(D minPos([2, 3, 1, 3, 4,
1])) returns the subrange $(D [1, 3, 4, 1]), i.e., positions the range
at the first occurrence of its minimal element.))
$(TR $(TDNW $(LREF skipOver)) $(TD Assume $(D a = "blah"). Then
$(D skipOver(a, "bi")) leaves $(D a) unchanged and returns $(D false),
whereas $(D skipOver(a, "bl")) advances $(D a) to refer to $(D "ah")
and returns $(D true).))
$(TR $(TDNW $(LREF startsWith)) $(TD $(D startsWith("hello,
world", "hello")) returns $(D true).))
$(TR $(TDNW $(LREF until)) $(TD Lazily iterates a range
until a specific value is found.))
$(LEADINGROW Comparison)
$(TR $(TDNW $(LREF cmp)) $(TD $(D cmp("abc", "abcd")) is $(D
-1), $(D cmp("abc", aba")) is $(D 1), and $(D cmp("abc", "abc")) is
$(D 0).))
$(TR $(TDNW $(LREF equal)) $(TD Compares ranges for
element-by-element equality, e.g. $(D equal([1, 2, 3], [1.0, 2.0,
3.0])) returns $(D true).))
$(TR $(TDNW $(LREF levenshteinDistance)) $(TD $(D
levenshteinDistance("kitten", "sitting")) returns $(D 3) by using the
$(LUCKY Levenshtein distance _algorithm).))
$(TR $(TDNW $(LREF levenshteinDistanceAndPath)) $(TD $(D
levenshteinDistanceAndPath("kitten", "sitting")) returns $(D tuple(3,
"snnnsni")) by using the $(LUCKY Levenshtein distance _algorithm).))
$(TR $(TDNW $(LREF max)) $(TD $(D max(3, 4, 2)) returns $(D
4).))
$(TR $(TDNW $(LREF min)) $(TD $(D min(3, 4, 2)) returns $(D
2).))
$(TR $(TDNW $(LREF mismatch)) $(TD $(D mismatch("oh hi",
"ohayo")) returns $(D tuple(" hi", "ayo")).))
$(LEADINGROW Iteration)
$(TR $(TDNW $(LREF filter)) $(TD $(D filter!"a > 0"([1, -1, 2,
0, -3])) iterates over elements $(D 1), $(D 2), and $(D 0).))
$(TR $(TDNW $(LREF filterBidirectional)) $(TD Similar to $(D
filter), but also provides $(D back) and $(D popBack) at a small
increase in cost.))
$(TR $(TDNW $(LREF group)) $(TD $(D group([5, 2, 2, 3, 3]))
returns a range containing the tuples $(D tuple(5, 1)), $(D tuple(5,
1)), $(D tuple(2, 2)), and $(D tuple(3, 2)).))
$(TR $(TDNW $(LREF joiner)) $(TD $(D joiner(["hello",
"world!"], ";")) returns a range that iterates over the characters $(D
"hello; world!"). No new string is created - the existing inputs are
iterated.))
$(TR $(TDNW $(LREF map)) $(TD $(D map!"2 * a"([1, 2, 3]))
lazily returns a range with the numbers $(D 2), $(D 4), $(D 6).))
$(TR $(TDNW $(LREF reduce)) $(TD $(D reduce!"a + b"([1, 2, 3,
4])) returns $(D 10).))
$(TR $(TDNW $(LREF splitter)) $(TD Lazily splits a range by a
separator.))
$(TR $(TDNW $(LREF uniq)) $(TD Iterates over the unique elements
in a range, which is assumed sorted.))
$(LEADINGROW Sorting)
$(TR $(TDNW $(LREF completeSort)) $(TD If $(D a = [10, 20, 30])
and $(D b = [40, 6, 15]), then $(D completeSort(a, b)) leaves $(D a =
[6, 10, 15]) and $(D b = [20, 30, 40]). The range $(D a) must be
sorted prior to the call, and as a result the combination $(D $(XREF
range,chain)(a, b)) is sorted.))
$(TR $(TDNW $(LREF isPartitioned)) $(TD $(D isPartitioned!"a <
0"([-1, -2, 1, 0, 2])) returns $(D true) because the predicate is $(D
true) for a portion of the range and $(D false) afterwards.))
$(TR $(TDNW $(LREF isSorted)) $(TD $(D isSorted([1, 1, 2, 3]))
returns $(D true).))
$(TR $(TDNW $(LREF makeIndex)) $(TD Creates a separate index
for a range.))
$(TR $(TDNW $(LREF partialSort)) $(TD If $(D a = [5, 4, 3, 2,
1]), then $(D partialSort(a, 3)) leaves $(D a[0 .. 3] = [1, 2,
3]). The other elements of $(D a) are left in an unspecified order.))
$(TR $(TDNW $(LREF partition)) $(TD Partitions a range
according to a predicate.))
$(TR $(TDNW $(LREF schwartzSort)) $(TD Sorts with the help of
the $(LUCKY Schwartzian transform).))
$(TR $(TDNW $(LREF sort)) $(TD Sorts.))
$(TR $(TDNW $(LREF topN)) $(TD Separates the top elements in a
range.))
$(TR $(TDNW $(LREF topNCopy)) $(TD Copies out the top elements
of a range.))
$(LEADINGROW Set operations)
$(TR $(TDNW $(LREF largestPartialIntersection)) $(TD Copies out
the values that occur most frequently in a range of ranges.))
$(TR $(TDNW $(LREF largestPartialIntersectionWeighted)) $(TD
Copies out the values that occur most frequently (multiplied by
per-value weights) in a range of ranges.))
$(TR $(TDNW $(LREF nWayUnion)) $(TD Computes the union of a set
of sets implemented as a range of sorted ranges.))
$(TR $(TDNW $(LREF setDifference)) $(TD Lazily computes the set
difference of two or more sorted ranges.))
$(TR $(TDNW $(LREF setIntersection)) $(TD Lazily computes the
set difference of two or more sorted ranges.))
$(TR $(TDNW $(LREF setSymmetricDifference)) $(TD Lazily
computes the symmetric set difference of two or more sorted ranges.))
$(TR $(TDNW $(LREF setUnion)) $(TD Lazily computes the set
union of two or more sorted ranges.))
$(LEADINGROW Mutation)
$(TR $(TDNW $(LREF bringToFront)) $(TD If $(D a = [1, 2, 3])
and $(D b = [4, 5, 6, 7]), $(D bringToFront(a, b)) leaves $(D a = [4,
5, 6]) and $(D b = [7, 1, 2, 3]).))
$(TR $(TDNW $(LREF copy)) $(TD Copies a range to another. If
$(D a = [1, 2, 3]) and $(D b = new int[5]), then $(D copy(a, b))
leaves $(D b = [1, 2, 3, 0, 0]) and returns $(D b[3 .. $]).))
$(TR $(TDNW $(LREF fill)) $(TD Fills a range with a pattern,
e.g., if $(D a = new int[3]), then $(D fill(a, 4)) leaves $(D a = [4,
4, 4]) and $(D fill(a, [3, 4])) leaves $(D a = [3, 4, 3]).))
$(TR $(TDNW $(LREF initializeAll)) $(TD If $(D a = [1.2, 3.4]),
then $(D initializeAll(a)) leaves $(D a = [double.init,
double.init]).))
$(TR $(TDNW $(LREF move)) $(TD $(D move(a, b)) moves $(D a)
into $(D b). $(D move(a)) reads $(D a) destructively.))
$(TR $(TDNW $(LREF moveAll)) $(TD Moves all elements from one
range to another.))
$(TR $(TDNW $(LREF moveSome)) $(TD Moves as many elements as
possible from one range to another.))
$(TR $(TDNW $(LREF reverse)) $(TD If $(D a = [1, 2, 3]), $(D
reverse(a)) changes it to $(D [3, 2, 1]).))
$(TR $(TDNW $(LREF swap)) $(TD Swaps two values.))
$(TR $(TDNW $(LREF swapRanges)) $(TD Swaps all elements of two
ranges.))
$(TR $(TDNW $(LREF uninitializedFill)) $(TD Fills a range
(assumed uninitialized) with a value.))
)
Macros:
WIKI = Phobos/StdAlgorithm
MYREF = <font face='Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace'><a href="#$1">$1</a>&nbsp;</font>
Copyright: Andrei Alexandrescu 2008-.
@ -96,34 +362,32 @@ separately:
alias map!(to!string) stringize;
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
----
*/
template map(fun...)
*/
template map(fun...) if (fun.length >= 1)
{
auto map(Range)(Range r)
auto map(Range)(Range r) if (isInputRange!(Unqual!Range))
{
static if (fun.length > 1)
{
return Map!(adjoin!(staticMap!(unaryFun, fun)), Range)(r);
alias adjoin!(staticMap!(unaryFun, fun)) pred;
}
else
{
return Map!(unaryFun!fun, Range)(r);
alias unaryFun!fun pred;
}
}
}
struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
{
struct Result
{
alias Unqual!Range R;
alias fun _fun;
alias pred _fun;
// Uncomment this to reveal a @@@BUG@@@ in the compiler
//alias typeof(fun(.ElementType!R.init)) ElementType;
alias typeof({ return fun(.ElementType!R.init); }()) ElementType;
alias typeof({ return pred(.ElementType!R.init); }()) ElementType;
R _input;
static if (isBidirectionalRange!(R))
static if (isBidirectionalRange!R)
{
@property ElementType back()
@property auto ref back()
{
return _fun(_input.back);
}
@ -157,14 +421,14 @@ struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
_input.popFront();
}
@property ElementType front()
@property auto ref front()
{
return _fun(_input.front);
}
static if (isRandomAccessRange!R)
{
ElementType opIndex(size_t index)
auto ref opIndex(size_t index)
{
return _fun(_input[index]);
}
@ -180,21 +444,25 @@ struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
}
}
static if (hasSlicing!(R))
static if (hasSlicing!R)
{
typeof(this) opSlice(size_t lowerBound, size_t upperBound)
auto opSlice(size_t lowerBound, size_t upperBound)
{
return typeof(this)(_input[lowerBound..upperBound]);
}
}
static if (isForwardRange!R)
@property Map save()
@property auto save()
{
auto result = this;
result._input = result._input.save;
return result;
}
}
return Result(r);
}
}
unittest
@ -360,7 +628,7 @@ auto stdev = sqrt(r[1] / a.length - avg * avg);
----
*/
template reduce(fun...)
template reduce(fun...) if (fun.length >= 1)
{
auto reduce(Args...)(Args args)
if (Args.length > 0 && Args.length <= 2 && isIterable!(Args[$ - 1]))
@ -404,8 +672,7 @@ template reduce(fun...)
result = void;
foreach (i, T; result.Types)
{
auto p = (cast(void*) &result[i])[0 .. result[i].sizeof];
emplace!T(p, r.front);
emplace(&result[i], r.front);
}
r.popFront();
return reduce(result, r);
@ -467,9 +734,7 @@ template reduce(fun...)
foreach (i, T; result.Types)
{
auto p = (cast(void*) &result[i])
[0 .. result[i].sizeof];
emplace!T(p, elem);
emplace(&result[i], elem);
}
}
}
@ -638,7 +903,6 @@ fill(a, b);
assert(a == [ 8, 9, 8, 9, 8 ]);
----
*/
void fill(Range1, Range2)(Range1 range, Range2 filler)
if (isForwardRange!Range1 && isForwardRange!Range2
&& is(typeof(Range1.init.front = Range2.init.front)))
@ -685,7 +949,7 @@ if (isForwardRange!Range && is(typeof(range.front = filler)))
// Must construct stuff by the book
for (; !range.empty; range.popFront)
{
emplace!T((cast(void*) &range.front)[0 .. T.sizeof], filler);
emplace(&range.front, filler);
}
}
else
@ -804,29 +1068,25 @@ auto r1 = filter!("cast(int) a != a")(chain(c, a, b));
assert(equal(r1, [ 2.5 ]));
----
*/
template filter(alias pred)
template filter(alias pred) //if (is(typeof(unaryFunction!pred)))
{
auto filter(Range)(Range rs)
auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range))
{
struct Result
{
return Filter!(unaryFun!(pred), Range)(rs);
}
}
struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
{
alias Unqual!Range R;
R _input;
this(R r)
{
_input = r;
while (!_input.empty && !pred(_input.front)) _input.popFront;
while (!_input.empty && !unaryFun!pred(_input.front))
{
_input.popFront();
}
}
ref Filter opSlice()
{
return this;
}
auto opSlice() { return this; }
static if (isInfinite!Range)
{
@ -842,7 +1102,7 @@ struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
do
{
_input.popFront;
} while (!_input.empty && !pred(_input.front));
} while (!_input.empty && !unaryFun!pred(_input.front));
}
@property auto ref front()
@ -852,11 +1112,15 @@ struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
static if(isForwardRange!R)
{
@property typeof(this) save()
@property auto save()
{
return typeof(this)(_input);
return Result(_input);
}
}
}
return Result(rs);
}
}
unittest
@ -921,7 +1185,8 @@ unittest
a = [ 1, 22, 3, 42, 5 ];
auto under10 = filter!("a < 10")(a);
assert(equal(under10, [1, 3, 5][]));
assert(under10.save == under10);
assert(equal(under10.save, [1, 3, 5][]));
assert(equal(under10.save, under10));
// With copying of inner struct Filter to Map
auto arr = [1,2,3,4,5];
@ -969,23 +1234,19 @@ assert(r.back == 102);
*/
template filterBidirectional(alias pred)
{
FilterBidirectional!(unaryFun!(pred), Range)
filterBidirectional(Range)(Range rs)
auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range))
{
static struct Result
{
return typeof(return)(rs);
}
}
struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!Range))
{
alias Unqual!Range R;
alias unaryFun!pred predFun;
R _input;
this(R r)
{
_input = r;
while (!_input.empty && !pred(_input.front)) _input.popFront();
while (!_input.empty && !pred(_input.back)) _input.popBack();
while (!_input.empty && !predFun(_input.front)) _input.popFront();
while (!_input.empty && !predFun(_input.back)) _input.popBack();
}
@property bool empty() { return _input.empty; }
@ -995,7 +1256,7 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
do
{
_input.popFront;
} while (!_input.empty && !pred(_input.front));
} while (!_input.empty && !predFun(_input.front));
}
@property auto ref front()
@ -1008,7 +1269,7 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
do
{
_input.popBack;
} while (!_input.empty && !pred(_input.back));
} while (!_input.empty && !predFun(_input.back));
}
@property auto ref back()
@ -1016,9 +1277,15 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
return _input.back;
}
@property typeof(this) save()
@property auto save()
{
return typeof(this)(_input);
Result result;
result._input = _input.save;
return result;
}
}
return Result(r);
}
}
@ -1122,6 +1389,8 @@ Preconditions:
$(D walkLength(src) >= walkLength(tgt))
*/
Range2 moveAll(Range1, Range2)(Range1 src, Range2 tgt)
if (isInputRange!Range1 && isInputRange!Range2
&& is(typeof(move(src.front, tgt.front))))
{
for (; !src.empty; src.popFront, tgt.popFront)
{
@ -1150,6 +1419,8 @@ when either $(D src) or $(D tgt) have been exhausted. Returns the
leftover portions of the two ranges.
*/
Tuple!(Range1, Range2) moveSome(Range1, Range2)(Range1 src, Range2 tgt)
if (isInputRange!Range1 && isInputRange!Range2
&& is(typeof(move(src.front, tgt.front))))
{
for (; !src.empty && !tgt.empty; src.popFront, tgt.popFront)
{
@ -1315,10 +1586,12 @@ a = [ 0, 1 ];
assert(equal(splitter(a, 0), [ [], [1] ]));
----
*/
struct Splitter(Range, Separator)
if (is(typeof(ElementType!Range.init == Separator.init)) && hasSlicing!Range)
auto splitter(Range, Separator)(Range r, Separator s)
if (is(typeof(ElementType!Range.init == Separator.init)) && hasSlicing!Range)
{
private:
struct Result
{
private:
Range _input;
Separator _separator;
enum size_t _unComputed = size_t.max - 1, _atEnd = size_t.max;
@ -1334,7 +1607,7 @@ private:
}
}
public:
public:
this(Range input, Separator separator)
{
_input = input;
@ -1437,7 +1710,7 @@ public:
else
{
_input = _input[0 .. _input.length - _backLength];
if(!_input.empty && _input.back == _separator)
if (!_input.empty && _input.back == _separator)
{
_input.popBack();
}
@ -1449,17 +1722,9 @@ public:
}
}
}
}
}
/// Ditto
Splitter!(Range, Separator)
splitter(Range, Separator)(Range r, Separator s)
if (is(typeof(ElementType!Range.init == ElementType!Separator.init))
||
is(typeof(ElementType!Range.init == Separator.init))
)
{
return typeof(return)(r, s);
return Result(r, s);
}
unittest
@ -1528,10 +1793,12 @@ unittest
Splits a range using another range as a separator. This can be used
with any range type, but is most popular with string types.
*/
struct Splitter(Range, Separator)
auto splitter(Range, Separator)(Range r, Separator s)
if (is(typeof(Range.init.front == Separator.init.front) : bool))
{
private:
struct Result
{
private:
Range _input;
Separator _separator;
// _frontLength == size_t.max means empty
@ -1560,11 +1827,11 @@ private:
static if (isBidirectionalRange!Range)
{
_backLength = _input.length -
find(retro(_input), retro(_separator)).length;
find(retro(_input), retro(_separator)).source.length;
}
}
public:
public:
this(Range input, Separator separator)
{
_input = input;
@ -1664,6 +1931,9 @@ public:
_backLength = _backLength.max;
}
}
}
return Result(r, s);
}
unittest
@ -1718,12 +1988,11 @@ unittest
assert(equal(sp6, ["", ""][]));
}
struct Splitter(alias isTerminator, Range,
Slice = Select!(is(typeof(Range.init[0 .. 1])),
Range,
ElementType!(Range)[]))
if(!is(isTerminator))
auto splitter(alias isTerminator, Range)(Range input)
if (is(typeof(unaryFun!(isTerminator)(ElementType!(Range).init))))
{
struct Result
{
private Range _input;
private size_t _end;
private alias unaryFun!isTerminator _isTerminator;
@ -1807,13 +2076,9 @@ if(!is(isTerminator))
return ret;
}
}
}
}
Splitter!(isTerminator, Range)
splitter(alias isTerminator, Range)(Range input)
if (is(typeof(unaryFun!(isTerminator)(ElementType!(Range).init))))
{
return typeof(return)(input);
return Result(input);
}
unittest
@ -2096,16 +2361,19 @@ int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][]));
----
*/
struct Uniq(alias pred, R)
auto uniq(alias pred = "a == b", Range)(Range r)
if (isInputRange!Range && is(typeof(binaryFun!pred(r.front, r.front)) == bool))
{
R _input;
struct Result
{
Range _input;
this(R input)
this(Range input)
{
_input = input;
}
ref Uniq opSlice()
auto opSlice()
{
return this;
}
@ -2120,9 +2388,9 @@ struct Uniq(alias pred, R)
while (!_input.empty && binaryFun!(pred)(last, _input.front));
}
@property ElementType!(R) front() { return _input.front; }
@property ElementType!Range front() { return _input.front; }
static if (isBidirectionalRange!R)
static if (isBidirectionalRange!Range)
{
void popBack()
{
@ -2131,13 +2399,13 @@ struct Uniq(alias pred, R)
{
_input.popBack;
}
while (!_input.empty && binaryFun!(pred)(last, _input.back));
while (!_input.empty && binaryFun!pred(last, _input.back));
}
@property ElementType!(R) back() { return _input.back; }
@property ElementType!Range back() { return _input.back; }
}
static if (isInfinite!R)
static if (isInfinite!Range)
{
enum bool empty = false; // Propagate infiniteness.
}
@ -2147,17 +2415,14 @@ struct Uniq(alias pred, R)
}
static if (isForwardRange!R) {
static if (isForwardRange!Range) {
@property typeof(this) save() {
return typeof(this)(_input.save);
}
}
}
}
/// Ditto
Uniq!(pred, Range) uniq(alias pred = "a == b", Range)(Range r)
{
return typeof(return)(r);
return Result(r);
}
unittest
@ -5916,9 +6181,15 @@ sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
{
sortImpl!(lessFun, ss)(r);
static if(is(typeof(text(r))))
assert(isSorted!lessFun(r), text(Range.stringof, ": ", r));
{
enum maxLen = 8;
assert(isSorted!lessFun(r), text("Failed to sort range of type ",
Range.stringof, ". Actual result is: ",
r[0 .. maxLen], r.length > maxLen ? "..." : ""));
}
else
assert(isSorted!lessFun(r), text(Range.stringof, ": <unable to print elements>"));
assert(isSorted!lessFun(r), text("Unable to sort range of type ",
Range.stringof, ": <unable to print elements>"));
}
else
{
@ -6169,7 +6440,7 @@ created.
To check whether an array was sorted and benefit of the speedup of
Schwartz sorting, a function $(D schwartzIsSorted) is not provided
because the effect can be achieved by calling $(D
isSorted!(less)(map!(transform)(r))).
isSorted!less(map!transform(r))).
*/
void schwartzSort(alias transform, alias less = "a < b",
SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)

View file

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

View file

@ -7,7 +7,6 @@ Source: $(PHOBOSSRC std/_container.d)
Macros:
WIKI = Phobos/StdContainer
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 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)
{
auto orig = r.original;
auto orig = r.source;
if (!orig._head)
{
// Inserting after a null range counts as insertion to the
@ -1287,7 +1286,7 @@ Complexity: $(BIGOH n)
*/
Range linearRemove(Take!Range r)
{
auto orig = r.original;
auto orig = r.source;
// We have something to remove here
if (orig._head == _root)
{
@ -1571,9 +1570,7 @@ struct Array(T) if (!is(T : const(bool)))
reserve(1 + capacity * 3 / 2);
}
assert(capacity > length && _payload.ptr);
emplace!T((cast(void*) (_payload.ptr + _payload.length))
[0 .. T.sizeof],
stuff);
emplace(_payload.ptr + _payload.length, stuff);
_payload = _payload.ptr[0 .. _payload.length + 1];
return 1;
}
@ -1605,17 +1602,17 @@ struct Array(T) if (!is(T : const(bool)))
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)
{
GC.addRange(p, T.sizeof * values.length);
}
foreach (i, e; values)
{
emplace!T(p[i * T.sizeof .. (i + 1) * T.sizeof], e);
assert((cast(T*) p)[i] == e);
emplace(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,
_data._payload.ptr + r._a,
T.sizeof * (length - r._a));
emplace!T((cast(void*) (_data._payload.ptr + r._a))[0 .. T.sizeof],
stuff);
emplace(_data._payload.ptr + r._a, stuff);
_data._payload = _data._payload.ptr[0 .. _data._payload.length + 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 ..
_data._payload.ptr + r._a + extra)
{
emplace!T((cast(void*) p)[0 .. T.sizeof], stuff.front);
emplace(p, stuff.front);
stuff.popFront();
}
_data._payload =

View file

@ -3048,7 +3048,6 @@ version (none)
assert(to!string(cr) == to!string(creal.nan));
assert(feq(cr, creal.nan));
}
}
/* **************************************************************
@ -3956,7 +3955,8 @@ template octal(alias s) if (isIntegral!(typeof(s))) {
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
auto w = octal!"100_000_000_000";
static assert(!is(typeof(w) == int));
@ -4022,45 +4022,63 @@ T toImpl(T, S)(S src) if (is(T == struct) && is(typeof(T(src))))
// Bugzilla 3961
unittest
{
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__,
" succeeded.");
struct Int { int x; }
Int i = to!Int(1);
}
// emplace
/**
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). The $(D chunk) must be as least as large as $(D
T) needs and should have an alignment multiple of $(D T)'s alignment.
Given a pointer $(D chunk) to uninitialized memory (but already typed
as $(D T)), constructs an object of non-$(D class) type $(D T) at that
address.
This function can be $(D @trusted) if the corresponding constructor of
$(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,
new ConvException("emplace: target size too small"));
auto a = cast(size_t) chunk.ptr;
version (OSX) // for some reason, breaks on other platforms
enforce(a % T.alignof == 0, new ConvException("misalignment"));
auto result = cast(typeof(return)) chunk.ptr;
auto result = cast(typeof(return)) chunk;
static T i;
memcpy(result, &i, T.sizeof);
return result;
}
/**
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()
{
static T i;
memcpy(chunk.ptr, &i, T.sizeof);
memcpy(chunk, &i, T.sizeof);
}
static if (Args.length == 0)
{
// Just initialize the thing
initialize();
}
else static if (is(T == struct))
{
static if (is(typeof(result.__ctor(args))))
{
// T defines a genuine constructor accepting args
@ -4072,64 +4090,18 @@ T* emplace(T, Args...)(void[] chunk, Args args) if (!is(T == class))
{
// 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))
else //static if (Args.length == 1 && is(Args[0] : T))
{
initialize();
static assert(Args.length == 1);
//static assert(0, T.stringof ~ " " ~ Args.stringof);
// initialize();
*result = args[0];
}
}
else static if (Args.length == 1 && is(Args[0] : T))
{
// Primitive type. Assignment is fine for initialization.
*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;
}
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)
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;
}
/**
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
{
debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
@ -4200,7 +4226,6 @@ unittest
}
Foo foo;
auto voidArr = (cast(void*) &foo)[0..Foo.sizeof];
emplace!Foo(voidArr, 2U);
emplace!Foo(&foo, 2U);
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
@ -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.)
@ -32189,7 +32189,7 @@ unittest
}
version(D_Ddoc)
version(StdDdoc)
{
version(Windows) {}
else
@ -32982,37 +32982,29 @@ 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)
{
/++
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, $(D
func) will run. $(D func) is a unary function that takes a $(D
TickDuration).
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).
Examples:
Examples:
--------------------
writeln("benchmark start!");
{
auto mt = measureTime!((a){assert(a.seconds);});
doSomething();
auto mt = measureTime!((a){assert(a.seconds);});
doSomething();
}
writeln("benchmark end!");
--------------------
+/
auto measureTime(alias func)();
}
else
+/
@safe auto measureTime(alias func)()
if(isSafe!func)
{
@safe
{
auto measureTime(alias func)()
if(isSafe!func)
{
struct TMP
struct Result
{
private StopWatch sw = void;
this(StopWatch.AutoStart as)
@ -33024,15 +33016,11 @@ else
unaryFun!(func)(sw.peek());
}
}
return TMP(autoStart);
}
}
return Result(autoStart);
}
@system
{
auto measureTime(alias func)()
if (!isSafe!func)
{
@system auto measureTime(alias func)() if (!isSafe!func)
{
struct TMP
{
private StopWatch sw = void;
@ -33046,12 +33034,9 @@ else
}
}
return TMP(autoStart);
}
}
}
@system
unittest
@system unittest
{
version(testStdDateTime)
{

View file

@ -601,7 +601,7 @@ unittest
* $(RED Scheduled for deprecation. Please use getTimesWin (for Windows)
* or getTimesPosix (for Posix) instead.)
*/
version(D_Ddoc)
version(StdDdoc)
{
void getTimes(in char[] name,
out d_time ftc,
@ -668,7 +668,7 @@ else
static assert(0, "Unsupported/Unknown OS");
version(D_Ddoc)
version(StdDdoc)
{
/++
$(BLUE This function is Windows-Only.)
@ -877,7 +877,7 @@ else
static assert(0, "Unsupported/Unknown OS");
version(D_Ddoc)
version(StdDdoc)
{
/++
$(RED Scheduled for deprecation. Please use
@ -911,7 +911,7 @@ else
}
version(D_Ddoc)
version(StdDdoc)
{
/++
$(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
@ -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.
@ -2497,7 +2497,7 @@ version(Posix) void copy(in char[] from, in char[] to)
cenforce(utime(toz, &utim) != -1, from);
}
version(D_Ddoc)
version(StdDdoc)
{
/++
$(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).

View file

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

View file

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

View file

@ -878,7 +878,7 @@ auto a = uniform(0, 1024, gen);
auto a = uniform(0.0f, 1.0f, gen);
----
*/
version(D_Ddoc)
version(StdDdoc)
CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)",
T1, T2, UniformRandomNumberGenerator)
(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).
*/
version(D_Ddoc)
version(StdDdoc)
CommonType!(T1, T2) uniform(string boundaries = "[$(RPAREN)", T1, T2)
(T1 a, T2 b) if (!is(CommonType!(T1, T2) == void));
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
----
*/
size_t dice(R, Num)(ref R rnd, Num[] proportions...)
if(isNumeric!Num) {
size_t dice(Rng, Num)(ref Rng rnd, Num[] proportions...)
if (isNumeric!Num && isForwardRange!Rng)
{
return diceImpl(rnd, proportions);
}
/// Ditto
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);
}
/// Ditto
size_t dice(Num)(Num[] proportions...)
if(isNumeric!Num) {
size_t dice(Range)(Range proportions)
if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range)
{
return diceImpl(rndGen(), proportions);
}
/// Ditto
size_t dice(Range)(Range proportions)
if(isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) {
size_t dice(Num)(Num[] proportions...)
if (isNumeric!Num)
{
return diceImpl(rndGen(), proportions);
}
private size_t diceImpl(R, Range)(ref R rnd, Range proportions)
if(isForwardRange!Range && isNumeric!(ElementType!Range)) {
immutable sum = reduce!("(assert(b >= 0), a + b)")(0.0, proportions.save);
private size_t diceImpl(Rng, Range)(ref Rng rng, Range proportions)
if (isForwardRange!Range && isNumeric!(ElementType!Range) && isForwardRange!Rng)
{
double sum = reduce!("(assert(b >= 0), a + b)")(0.0, proportions.save);
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);
auto mass = 0.0;
@ -1123,8 +1128,6 @@ if(isForwardRange!Range && isNumeric!(ElementType!Range)) {
assert(false);
}
unittest {
auto rnd = Random(unpredictableSeed);
auto i = dice(rnd, 0.0, 100.0);
@ -1132,13 +1135,7 @@ unittest {
i = dice(rnd, 100.0, 0.0);
assert(i == 0);
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]));
i = dice(100U, 0U);
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);
}
/**
* 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.

View file

@ -2286,7 +2286,7 @@ if (!is(T == class))
{
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._count = 1;
debug(RefCounted) if (debugging) writeln(typeof(this).stringof,