mirror of
https://github.com/dlang/phobos.git
synced 2025-04-30 23:20:29 +03:00
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:
parent
69d8b2e514
commit
1083bd4e7b
13 changed files with 2861 additions and 2420 deletions
13
posix.mak
13
posix.mak
|
@ -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
|
||||
|
||||
|
|
461
std/algorithm.d
461
std/algorithm.d
|
@ -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 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> </font>
|
||||
|
||||
Copyright: Andrei Alexandrescu 2008-.
|
||||
|
||||
|
@ -97,33 +363,31 @@ 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,16 +444,16 @@ 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;
|
||||
|
@ -197,6 +461,10 @@ struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
|
|||
}
|
||||
}
|
||||
|
||||
return Result(r);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(std_algorithm) scope(success)
|
||||
|
@ -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,15 +1068,11 @@ 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))
|
||||
{
|
||||
return Filter!(unaryFun!(pred), Range)(rs);
|
||||
}
|
||||
}
|
||||
|
||||
struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
|
||||
struct Result
|
||||
{
|
||||
alias Unqual!Range R;
|
||||
R _input;
|
||||
|
@ -820,13 +1080,13 @@ struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
|
|||
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,13 +1112,17 @@ 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
|
||||
{
|
||||
debug(std_algorithm) scope(success)
|
||||
|
@ -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))
|
||||
{
|
||||
return typeof(return)(rs);
|
||||
}
|
||||
}
|
||||
|
||||
struct FilterBidirectional(alias pred, Range) if (isBidirectionalRange!(Unqual!Range))
|
||||
static struct Result
|
||||
{
|
||||
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,8 +1586,10 @@ 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)
|
||||
{
|
||||
struct Result
|
||||
{
|
||||
private:
|
||||
Range _input;
|
||||
|
@ -1451,15 +1724,7 @@ 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,8 +1793,10 @@ 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))
|
||||
{
|
||||
struct Result
|
||||
{
|
||||
private:
|
||||
Range _input;
|
||||
|
@ -1560,7 +1827,7 @@ private:
|
|||
static if (isBidirectionalRange!Range)
|
||||
{
|
||||
_backLength = _input.length -
|
||||
find(retro(_input), retro(_separator)).length;
|
||||
find(retro(_input), retro(_separator)).source.length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1666,6 +1933,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
return Result(r, s);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(std_algorithm) scope(success)
|
||||
|
@ -1718,11 +1988,10 @@ 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;
|
||||
|
@ -1809,11 +2078,7 @@ if(!is(isTerminator))
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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 =
|
||||
|
|
175
std/conv.d
175
std/conv.d
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,16 +32982,14 @@ unittest
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
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:
|
||||
--------------------
|
||||
|
@ -33003,16 +33001,10 @@ doSomething();
|
|||
writeln("benchmark end!");
|
||||
--------------------
|
||||
+/
|
||||
auto measureTime(alias func)();
|
||||
}
|
||||
else
|
||||
{
|
||||
@safe
|
||||
{
|
||||
auto measureTime(alias func)()
|
||||
@safe auto measureTime(alias func)()
|
||||
if(isSafe!func)
|
||||
{
|
||||
struct TMP
|
||||
struct Result
|
||||
{
|
||||
private StopWatch sw = void;
|
||||
this(StopWatch.AutoStart as)
|
||||
|
@ -33024,14 +33016,10 @@ 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
|
||||
{
|
||||
|
@ -33047,11 +33035,8 @@ else
|
|||
}
|
||||
return TMP(autoStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@system
|
||||
unittest
|
||||
@system unittest
|
||||
{
|
||||
version(testStdDateTime)
|
||||
{
|
||||
|
|
16
std/file.d
16
std/file.d
|
@ -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).
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
41
std/random.d
41
std/random.d
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
1483
std/range.d
1483
std/range.d
File diff suppressed because it is too large
Load diff
23
std/traits.d
23
std/traits.d
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue