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 =
@ -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

View file

@ -1,14 +1,50 @@
// Written in the D programming language. // 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 Implements algorithms oriented mainly towards processing of
sequences. Some functions are semantic equivalents or supersets of sequences. Some functions are semantic equivalents or supersets of
those found in the $(D $(LESS)_algorithm$(GREATER)) header in $(WEB those found in the $(D $(LESS)_algorithm$(GREATER)) header in $(WEB
sgi.com/tech/stl/, Alexander Stepanov's Standard Template Library) for sgi.com/tech/stl/, Alexander Stepanov's Standard Template Library) for
C++. C++.
Note:
Many functions in this module are parameterized with a function or a Many functions in this module are parameterized with a function or a
$(GLOSSARY predicate). The predicate may be passed either as a $(GLOSSARY predicate). The predicate may be passed either as a
function name, a delegate name, a $(GLOSSARY functor) name, or 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 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: Macros:
WIKI = Phobos/StdAlgorithm 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-. Copyright: Andrei Alexandrescu 2008-.
@ -96,34 +362,32 @@ separately:
alias map!(to!string) stringize; alias map!(to!string) stringize;
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ])); 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) static if (fun.length > 1)
{ {
return Map!(adjoin!(staticMap!(unaryFun, fun)), Range)(r); alias adjoin!(staticMap!(unaryFun, fun)) pred;
} }
else 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 Unqual!Range R;
alias fun _fun; alias pred _fun;
// Uncomment this to reveal a @@@BUG@@@ in the compiler // Uncomment this to reveal a @@@BUG@@@ in the compiler
//alias typeof(fun(.ElementType!R.init)) ElementType; //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; R _input;
static if (isBidirectionalRange!(R)) static if (isBidirectionalRange!R)
{ {
@property ElementType back() @property auto ref back()
{ {
return _fun(_input.back); return _fun(_input.back);
} }
@ -157,14 +421,14 @@ struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
_input.popFront(); _input.popFront();
} }
@property ElementType front() @property auto ref front()
{ {
return _fun(_input.front); return _fun(_input.front);
} }
static if (isRandomAccessRange!R) static if (isRandomAccessRange!R)
{ {
ElementType opIndex(size_t index) auto ref opIndex(size_t index)
{ {
return _fun(_input[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]); return typeof(this)(_input[lowerBound..upperBound]);
} }
} }
static if (isForwardRange!R) static if (isForwardRange!R)
@property Map save() @property auto save()
{ {
auto result = this; auto result = this;
result._input = result._input.save; result._input = result._input.save;
return result; return result;
} }
}
return Result(r);
}
} }
unittest 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) auto reduce(Args...)(Args args)
if (Args.length > 0 && Args.length <= 2 && isIterable!(Args[$ - 1])) if (Args.length > 0 && Args.length <= 2 && isIterable!(Args[$ - 1]))
@ -404,8 +672,7 @@ template reduce(fun...)
result = void; result = void;
foreach (i, T; result.Types) foreach (i, T; result.Types)
{ {
auto p = (cast(void*) &result[i])[0 .. result[i].sizeof]; emplace(&result[i], r.front);
emplace!T(p, r.front);
} }
r.popFront(); r.popFront();
return reduce(result, r); return reduce(result, r);
@ -467,9 +734,7 @@ template reduce(fun...)
foreach (i, T; result.Types) foreach (i, T; result.Types)
{ {
auto p = (cast(void*) &result[i]) emplace(&result[i], elem);
[0 .. result[i].sizeof];
emplace!T(p, elem);
} }
} }
} }
@ -638,7 +903,6 @@ fill(a, b);
assert(a == [ 8, 9, 8, 9, 8 ]); assert(a == [ 8, 9, 8, 9, 8 ]);
---- ----
*/ */
void fill(Range1, Range2)(Range1 range, Range2 filler) void fill(Range1, Range2)(Range1 range, Range2 filler)
if (isForwardRange!Range1 && isForwardRange!Range2 if (isForwardRange!Range1 && isForwardRange!Range2
&& is(typeof(Range1.init.front = Range2.init.front))) && 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 // Must construct stuff by the book
for (; !range.empty; range.popFront) for (; !range.empty; range.popFront)
{ {
emplace!T((cast(void*) &range.front)[0 .. T.sizeof], filler); emplace(&range.front, filler);
} }
} }
else else
@ -804,29 +1068,25 @@ auto r1 = filter!("cast(int) a != a")(chain(c, a, b));
assert(equal(r1, [ 2.5 ])); 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; alias Unqual!Range R;
R _input; R _input;
this(R r) this(R r)
{ {
_input = r; _input = r;
while (!_input.empty && !pred(_input.front)) _input.popFront; while (!_input.empty && !unaryFun!pred(_input.front))
{
_input.popFront();
}
} }
ref Filter opSlice() auto opSlice() { return this; }
{
return this;
}
static if (isInfinite!Range) static if (isInfinite!Range)
{ {
@ -842,7 +1102,7 @@ struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
do do
{ {
_input.popFront; _input.popFront;
} while (!_input.empty && !pred(_input.front)); } while (!_input.empty && !unaryFun!pred(_input.front));
} }
@property auto ref front() @property auto ref front()
@ -852,11 +1112,15 @@ struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
static if(isForwardRange!R) static if(isForwardRange!R)
{ {
@property typeof(this) save() @property auto save()
{ {
return typeof(this)(_input); return Result(_input);
} }
} }
}
return Result(rs);
}
} }
unittest unittest
@ -921,7 +1185,8 @@ unittest
a = [ 1, 22, 3, 42, 5 ]; a = [ 1, 22, 3, 42, 5 ];
auto under10 = filter!("a < 10")(a); auto under10 = filter!("a < 10")(a);
assert(equal(under10, [1, 3, 5][])); 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 // With copying of inner struct Filter to Map
auto arr = [1,2,3,4,5]; auto arr = [1,2,3,4,5];
@ -969,23 +1234,19 @@ assert(r.back == 102);
*/ */
template filterBidirectional(alias pred) template filterBidirectional(alias pred)
{ {
FilterBidirectional!(unaryFun!(pred), Range) auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range))
filterBidirectional(Range)(Range rs) {
static struct Result
{ {
return typeof(return)(rs);
}
}
struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!Range))
{
alias Unqual!Range R; alias Unqual!Range R;
alias unaryFun!pred predFun;
R _input; R _input;
this(R r) this(R r)
{ {
_input = r; _input = r;
while (!_input.empty && !pred(_input.front)) _input.popFront(); while (!_input.empty && !predFun(_input.front)) _input.popFront();
while (!_input.empty && !pred(_input.back)) _input.popBack(); while (!_input.empty && !predFun(_input.back)) _input.popBack();
} }
@property bool empty() { return _input.empty; } @property bool empty() { return _input.empty; }
@ -995,7 +1256,7 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
do do
{ {
_input.popFront; _input.popFront;
} while (!_input.empty && !pred(_input.front)); } while (!_input.empty && !predFun(_input.front));
} }
@property auto ref front() @property auto ref front()
@ -1008,7 +1269,7 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
do do
{ {
_input.popBack; _input.popBack;
} while (!_input.empty && !pred(_input.back)); } while (!_input.empty && !predFun(_input.back));
} }
@property auto ref back() @property auto ref back()
@ -1016,9 +1277,15 @@ struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!R
return _input.back; 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)) $(D walkLength(src) >= walkLength(tgt))
*/ */
Range2 moveAll(Range1, Range2)(Range1 src, Range2 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) 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. leftover portions of the two ranges.
*/ */
Tuple!(Range1, Range2) moveSome(Range1, Range2)(Range1 src, Range2 tgt) 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) for (; !src.empty && !tgt.empty; src.popFront, tgt.popFront)
{ {
@ -1315,10 +1586,12 @@ a = [ 0, 1 ];
assert(equal(splitter(a, 0), [ [], [1] ])); assert(equal(splitter(a, 0), [ [], [1] ]));
---- ----
*/ */
struct Splitter(Range, Separator) auto splitter(Range, Separator)(Range r, Separator s)
if (is(typeof(ElementType!Range.init == Separator.init)) && hasSlicing!Range) if (is(typeof(ElementType!Range.init == Separator.init)) && hasSlicing!Range)
{ {
private: struct Result
{
private:
Range _input; Range _input;
Separator _separator; Separator _separator;
enum size_t _unComputed = size_t.max - 1, _atEnd = size_t.max; enum size_t _unComputed = size_t.max - 1, _atEnd = size_t.max;
@ -1334,7 +1607,7 @@ private:
} }
} }
public: public:
this(Range input, Separator separator) this(Range input, Separator separator)
{ {
_input = input; _input = input;
@ -1437,7 +1710,7 @@ public:
else else
{ {
_input = _input[0 .. _input.length - _backLength]; _input = _input[0 .. _input.length - _backLength];
if(!_input.empty && _input.back == _separator) if (!_input.empty && _input.back == _separator)
{ {
_input.popBack(); _input.popBack();
} }
@ -1449,17 +1722,9 @@ public:
} }
} }
} }
} }
/// Ditto return Result(r, s);
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);
} }
unittest unittest
@ -1528,10 +1793,12 @@ unittest
Splits a range using another range as a separator. This can be used Splits a range using another range as a separator. This can be used
with any range type, but is most popular with string types. 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)) if (is(typeof(Range.init.front == Separator.init.front) : bool))
{ {
private: struct Result
{
private:
Range _input; Range _input;
Separator _separator; Separator _separator;
// _frontLength == size_t.max means empty // _frontLength == size_t.max means empty
@ -1560,11 +1827,11 @@ private:
static if (isBidirectionalRange!Range) static if (isBidirectionalRange!Range)
{ {
_backLength = _input.length - _backLength = _input.length -
find(retro(_input), retro(_separator)).length; find(retro(_input), retro(_separator)).source.length;
} }
} }
public: public:
this(Range input, Separator separator) this(Range input, Separator separator)
{ {
_input = input; _input = input;
@ -1664,6 +1931,9 @@ public:
_backLength = _backLength.max; _backLength = _backLength.max;
} }
} }
}
return Result(r, s);
} }
unittest unittest
@ -1718,12 +1988,11 @@ unittest
assert(equal(sp6, ["", ""][])); assert(equal(sp6, ["", ""][]));
} }
struct Splitter(alias isTerminator, Range, auto splitter(alias isTerminator, Range)(Range input)
Slice = Select!(is(typeof(Range.init[0 .. 1])), if (is(typeof(unaryFun!(isTerminator)(ElementType!(Range).init))))
Range,
ElementType!(Range)[]))
if(!is(isTerminator))
{ {
struct Result
{
private Range _input; private Range _input;
private size_t _end; private size_t _end;
private alias unaryFun!isTerminator _isTerminator; private alias unaryFun!isTerminator _isTerminator;
@ -1807,13 +2076,9 @@ if(!is(isTerminator))
return ret; return ret;
} }
} }
} }
Splitter!(isTerminator, Range) return Result(input);
splitter(alias isTerminator, Range)(Range input)
if (is(typeof(unaryFun!(isTerminator)(ElementType!(Range).init))))
{
return typeof(return)(input);
} }
unittest 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 ][])); 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; _input = input;
} }
ref Uniq opSlice() auto opSlice()
{ {
return this; return this;
} }
@ -2120,9 +2388,9 @@ struct Uniq(alias pred, R)
while (!_input.empty && binaryFun!(pred)(last, _input.front)); 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() void popBack()
{ {
@ -2131,13 +2399,13 @@ struct Uniq(alias pred, R)
{ {
_input.popBack; _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. 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() { @property typeof(this) save() {
return typeof(this)(_input.save); return typeof(this)(_input.save);
} }
} }
} }
/// Ditto return Result(r);
Uniq!(pred, Range) uniq(alias pred = "a == b", Range)(Range r)
{
return typeof(return)(r);
} }
unittest unittest
@ -5916,9 +6181,15 @@ sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
{ {
sortImpl!(lessFun, ss)(r); sortImpl!(lessFun, ss)(r);
static if(is(typeof(text(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 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 else
{ {
@ -6169,7 +6440,7 @@ created.
To check whether an array was sorted and benefit of the speedup of To check whether an array was sorted and benefit of the speedup of
Schwartz sorting, a function $(D schwartzIsSorted) is not provided Schwartz sorting, a function $(D schwartzIsSorted) is not provided
because the effect can be achieved by calling $(D 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", void schwartzSort(alias transform, alias less = "a < b",
SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) 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)))) 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,45 +4022,63 @@ 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)
{
// Just initialize the thing
initialize();
}
else static if (is(T == struct))
{
static if (is(typeof(result.__ctor(args)))) static if (is(typeof(result.__ctor(args))))
{ {
// T defines a genuine constructor accepting 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 // Struct without constructor that has one matching field for
// each argument // each argument
initialize();
*result = T(args); *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]; *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; 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,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) 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)()
if(isSafe!func)
{
struct TMP
{ {
private StopWatch sw = void; private StopWatch sw = void;
this(StopWatch.AutoStart as) this(StopWatch.AutoStart as)
@ -33024,15 +33016,11 @@ else
unaryFun!(func)(sw.peek()); unaryFun!(func)(sw.peek());
} }
} }
return TMP(autoStart); return Result(autoStart);
} }
}
@system @system auto measureTime(alias func)() if (!isSafe!func)
{ {
auto measureTime(alias func)()
if (!isSafe!func)
{
struct TMP struct TMP
{ {
private StopWatch sw = void; private StopWatch sw = void;
@ -33046,12 +33034,9 @@ else
} }
} }
return TMP(autoStart); return TMP(autoStart);
}
}
} }
@system @system unittest
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,