diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-05 14:56:59 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-10 22:09:00 +0100 |
commit | 89629b271827357f81f6f8c7cf28f59919519864 (patch) | |
tree | bc6ae2e8d764a128cd9501b30ad96ce7e6360e85 /libphobos/src/std | |
parent | c9353e0fcd0ddc0d48ae8a2b0518f0f82670d708 (diff) | |
download | gcc-89629b271827357f81f6f8c7cf28f59919519864.zip gcc-89629b271827357f81f6f8c7cf28f59919519864.tar.gz gcc-89629b271827357f81f6f8c7cf28f59919519864.tar.bz2 |
d: Merge dmd, druntime 34875cd6e1, phobos ebd24da8a
D front-end changes:
- Import dmd v2.110.0-beta.1.
- `ref' can now be applied to local, static, extern, and global
variables.
D runtime changes:
- Import druntime v2.110.0-beta.1.
Phobos changes:
- Import phobos v2.110.0-beta.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 34875cd6e1.
* dmd/VERSION: Bump version to v2.110.0-beta.1.
* Make-lang.in (D_FRONTEND_OBJS): Add d/deps.o, d/timetrace.o.
* decl.cc (class DeclVisitor): Update for new front-end interface.
* expr.cc (class ExprVisitor): Likewise
* typeinfo.cc (check_typeinfo_type): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 34875cd6e1.
* src/MERGE: Merge upstream phobos ebd24da8a.
Diffstat (limited to 'libphobos/src/std')
23 files changed, 560 insertions, 451 deletions
diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d index fbef28e..e434d24 100644 --- a/libphobos/src/std/algorithm/mutation.d +++ b/libphobos/src/std/algorithm/mutation.d @@ -1071,10 +1071,20 @@ Params: copy is performed. */ void move(T)(ref T source, ref T target) +if (__traits(compiles, target = T.init)) { moveImpl(target, source); } +/// ditto +template move(T) +if (!__traits(compiles, imported!"std.traits".lvalueOf!T = T.init)) +{ + /// + deprecated("Can't move into `target` as `" ~ T.stringof ~ "` can't be assigned") + void move(ref T source, ref T target) => moveImpl(target, source); +} + /// For non-struct types, `move` just performs `target = source`: @safe unittest { @@ -1184,6 +1194,19 @@ pure nothrow @safe @nogc unittest assert(s53 is s51); } +@system unittest +{ + static struct S + { + immutable int i; + ~this() @safe {} + } + alias ol = __traits(getOverloads, std.algorithm.mutation, "move", true)[1]; + static assert(__traits(isDeprecated, ol!S)); + // uncomment after deprecation + //static assert(!__traits(compiles, { S a, b; move(a, b); })); +} + /// Ditto T move(T)(return scope ref T source) { diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d index c5b085d..2d16c65 100644 --- a/libphobos/src/std/algorithm/sorting.d +++ b/libphobos/src/std/algorithm/sorting.d @@ -2164,12 +2164,12 @@ private void quickSortImpl(alias less, Range)(Range r, size_t depth) { import std.algorithm.comparison : min, max; import std.algorithm.mutation : swap, swapAt; - import std.conv : to; alias Elem = ElementType!(Range); - enum size_t shortSortGetsBetter = max(32, 1024 / Elem.sizeof); + enum int size = Elem.sizeof; + enum size_t shortSortGetsBetter = max(32, 1024 / size); static assert(shortSortGetsBetter >= 1, Elem.stringof ~ " " - ~ to!string(Elem.sizeof)); + ~ size.stringof); // partition while (r.length > shortSortGetsBetter) diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d index 494fa29..1ce4a64 100644 --- a/libphobos/src/std/array.d +++ b/libphobos/src/std/array.d @@ -295,6 +295,19 @@ if (is(Range == U*, U) && isIterable!U && !isAutodecodableString!Range && !isInf R().array; } +// Test that `array(scope InputRange r)` returns a non-scope array +// https://issues.dlang.org/show_bug.cgi?id=23300 +@safe pure nothrow unittest +{ + @safe int[] fun() + { + import std.algorithm.iteration : map; + int[3] arr = [1, 2, 3]; + scope r = arr[].map!(x => x + 3); + return r.array; + } +} + /** Convert a narrow autodecoding string to an array type that fully supports random access. This is handled as a special case and always returns an array @@ -650,6 +663,8 @@ if (isInputRange!Values && isInputRange!Keys) alias ValueElement = ElementType!Values; static if (hasElaborateDestructor!ValueElement) ValueElement.init.__xdtor(); + + aa[key] = values.front; }))) { () @trusted { @@ -790,6 +805,20 @@ if (isInputRange!Values && isInputRange!Keys) assert(assocArray(1.iota, [UnsafeElement()]) == [0: UnsafeElement()]); } +@safe unittest +{ + struct ValueRange + { + string front() const @system; + @safe: + void popFront() {} + bool empty() const { return false; } + } + int[] keys; + ValueRange values; + static assert(!__traits(compiles, assocArray(keys, values))); +} + /** Construct a range iterating over an associative array by key/value tuples. diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d index 639b821..0993d34 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -1306,7 +1306,7 @@ public: /** Sets the bits of a slice of `BitArray` starting - at index `start` and ends at index ($D end - 1) + at index `start` and ends at index $(D end - 1) with the values specified by `val`. */ void opSliceAssign(bool val, size_t start, size_t end) @nogc pure nothrow diff --git a/libphobos/src/std/datetime/date.d b/libphobos/src/std/datetime/date.d index ebdaba4..7526f2d 100644 --- a/libphobos/src/std/datetime/date.d +++ b/libphobos/src/std/datetime/date.d @@ -3776,7 +3776,7 @@ public: enforceValid!"months"(cast(Month) month); enforceValid!"days"(year, cast(Month) month, day); - _year = cast(short) year; + _year = year.castToYear; _month = cast(Month) month; _day = cast(ubyte) day; } @@ -3814,6 +3814,7 @@ public: assertThrown!DateTimeException(Date(1999, 10, 32)); assertThrown!DateTimeException(Date(1999, 11, 31)); assertThrown!DateTimeException(Date(1999, 12, 32)); + assertThrown!DateTimeException(Date(short.max+1, 1, 1)); assertNotThrown!DateTimeException(Date(1999, 1, 31)); assertNotThrown!DateTimeException(Date(1999, 2, 28)); @@ -3839,6 +3840,7 @@ public: assertThrown!DateTimeException(Date(-1, 2, 29)); assertThrown!DateTimeException(Date(-2, 2, 29)); assertThrown!DateTimeException(Date(-3, 2, 29)); + assertThrown!DateTimeException(Date(short.min-1, 1, 1)); } @@ -4128,7 +4130,7 @@ public: @property void year(int year) @safe pure { enforceValid!"days"(year, _month, _day); - _year = cast(short) year; + _year = year.castToYear; } /// @@ -4215,7 +4217,7 @@ public: { if (year <= 0) throw new DateTimeException("The given year is not a year B.C."); - _year = cast(short)((year - 1) * -1); + _year = castToYear((year - 1) * -1); } /// @@ -9689,6 +9691,16 @@ if (units == "days") assert(!valid!"days"(2017, 2, 29)); } +private short castToYear(int year, string file = __FILE__, size_t line = __LINE__) @safe pure +{ + import std.conv : to, ConvOverflowException; + import std.format : format; + + try + return year.to!short; + catch (ConvOverflowException) + throw new DateTimeException(format("year %s doesn't fit to Date.", year), file, line); +} /++ Params: diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index b238918..4b6f27d 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -3339,7 +3339,7 @@ else version (Posix) Windows uses a different set of time zone names than the IANA time zone database does, and how they correspond to one another changes over time (particularly when Microsoft updates Windows). - $(HTTP unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml) + $(HTTP github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml, windowsZones.xml) provides the current conversions (which may or may not match up with what's on a particular Windows box depending on how up-to-date it is), and parseTZConversions reads in those conversions from windowsZones.xml so that @@ -3358,7 +3358,7 @@ else version (Posix) Params: windowsZonesXMLText = The text from - $(HTTP unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml) + $(HTTP github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml, windowsZones.xml) Throws: Exception if there is an error while parsing the given XML. @@ -3372,7 +3372,7 @@ else version (Posix) // and parse it so that it's guaranteed to be up-to-date, though // that has the downside that the code needs to worry about the // site being down or unicode.org changing the URL. - auto url = "http://unicode.org/cldr/data/common/supplemental/windowsZones.xml"; + auto url = "https://raw.githubusercontent.com/unicode-org/cldr/main/common/supplemental/windowsZones.xml"; auto conversions2 = parseTZConversions(std.net.curl.get(url)); -------------------- +/ @@ -3458,7 +3458,7 @@ TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure import std.algorithm.iteration : uniq; import std.algorithm.sorting : isSorted; - // Reduced text from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml + // Reduced text from https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml auto sampleFileText = `<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE supplementalData SYSTEM "../../common/dtd/ldmlSupplemental.dtd"> diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d index 58a667c..c3024d7 100644 --- a/libphobos/src/std/exception.d +++ b/libphobos/src/std/exception.d @@ -1540,9 +1540,9 @@ version (StdUnittest) } /+ -Returns true if the field at index `i` in ($D T) shares its address with another field. +Returns true if the field at index `i` in $(D T) shares its address with another field. -Note: This does not merelly check if the field is a member of an union, but also that +Note: This does not merely check if the field is a member of an union, but also that it is not a single child. +/ package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/package.d b/libphobos/src/std/experimental/allocator/building_blocks/package.d index 6bc527d..521d7ed 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/package.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/package.d @@ -43,7 +43,7 @@ alignedReallocate) APIs.)) $(TR $(TDC size_t goodAllocSize(size_t n);, $(POST $(RES) >= n)) $(TD Allocators customarily allocate memory in discretely-sized chunks. Therefore, a request for `n` bytes may result in a larger allocation. The extra memory allocated goes -unused and adds to the so-called $(HTTP goo.gl/YoKffF,internal fragmentation). +unused and adds to the so-called $(HTTPS en.wikipedia.org/wiki/Fragmentation_(computing)#Internal_fragmentation,internal fragmentation). The function `goodAllocSize(n)` returns the actual number of bytes that would be allocated upon a request for `n` bytes. This module defines a default implementation that returns `n` rounded up to a multiple of the allocator's @@ -137,7 +137,7 @@ thread-safe or not, this instance may be `shared`.)) $(H2 Sample Assembly) -The example below features an _allocator modeled after $(HTTP goo.gl/m7329l, +The example below features an _allocator modeled after $(HTTP jemalloc.net/, jemalloc), which uses a battery of free-list allocators spaced so as to keep internal fragmentation to a minimum. The `FList` definitions specify no bounds for the freelist because the `Segregator` does all size selection in diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d index a23746a..736b185 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/region.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d @@ -904,7 +904,7 @@ version (DragonFlyBSD) { // sbrk is deprecated in favor of mmap (we could implement a mmap + MAP_NORESERVE + PROT_NONE version) // brk has been removed - // https://www.dragonflydigest.com/2019/02/22/22586.html + // https://web.archive.org/web/20221006070113/https://www.dragonflydigest.com/2019/02/22/22586.html // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/dc676eaefa61b0f47bbea1c53eab86fd5ccd78c6 // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/4b5665564ef37dc939a3a9ffbafaab9894c18885 // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/8618d94a0e2ff8303ad93c123a3fa598c26a116e @@ -968,7 +968,7 @@ version (Posix) struct SbrkRegion(uint minAlign = platformAlignment) scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); // Assume sbrk returns the old break. Most online documentation confirms - // that, except for http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf, + // that, except for https://web.archive.org/web/20171014020821/http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf, // which claims the returned value is not portable. auto p = sbrk(rounded); if (p == cast(void*) -1) diff --git a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d index 3770af1..1d1e480 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d @@ -134,7 +134,7 @@ enum Options : ulong bytesNotMoved = 1u << 17, /** Measures the sum of extra bytes allocated beyond the bytes requested, i.e. - the $(HTTP goo.gl/YoKffF, internal fragmentation). This is the current + the $(HTTPS en.wikipedia.org/wiki/Fragmentation_(computing)#Internal_fragmentation, internal fragmentation). This is the current effective number of slack bytes, and it goes up and down with time. */ bytesSlack = 1u << 18, diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d index 3d4dc9a..087dbec 100644 --- a/libphobos/src/std/experimental/allocator/mallocator.d +++ b/libphobos/src/std/experimental/allocator/mallocator.d @@ -52,7 +52,7 @@ struct Mallocator import core.memory : pureRealloc; if (!s) { - // fuzzy area in the C standard, see http://goo.gl/ZpWeSE + // fuzzy area in the C standard, see https://stackoverflow.com/questions/6502077/malloc-and-realloc-functions // so just deallocate and nullify the pointer deallocate(b); b = null; diff --git a/libphobos/src/std/experimental/allocator/mmap_allocator.d b/libphobos/src/std/experimental/allocator/mmap_allocator.d index 4151d0e..494d5a3 100644 --- a/libphobos/src/std/experimental/allocator/mmap_allocator.d +++ b/libphobos/src/std/experimental/allocator/mmap_allocator.d @@ -60,7 +60,7 @@ struct MmapAllocator // http://man7.org/linux/man-pages/man2/mmap.2.html package alias allocateZeroed = allocate; else version (NetBSD) - // http://netbsd.gw.com/cgi-bin/man-cgi?mmap+2+NetBSD-current + // https://man.netbsd.org/mmap.2 package alias allocateZeroed = allocate; else version (Solaris) // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html diff --git a/libphobos/src/std/format/internal/read.d b/libphobos/src/std/format/internal/read.d index 9130499..597898c 100644 --- a/libphobos/src/std/format/internal/read.d +++ b/libphobos/src/std/format/internal/read.d @@ -161,15 +161,16 @@ if (isInputRange!Range && isSomeChar!T && !is(T == enum) && isSomeChar!(ElementT enforceFmt(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if (T.sizeof == 1) + enum int size = T.sizeof; + static if (size == 1) return unformatValue!ubyte(input, spec); - else static if (T.sizeof == 2) + else static if (size == 2) return unformatValue!ushort(input, spec); - else static if (T.sizeof == 4) + else static if (size == 4) return unformatValue!uint(input, spec); else static assert(false, T.stringof ~ ".sizeof must be 1, 2, or 4 not " ~ - to!string(T.sizeof)); + size.stringof); } T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char fmt) diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d index f1d4705..a78e1b3 100644 --- a/libphobos/src/std/format/package.d +++ b/libphobos/src/std/format/package.d @@ -358,7 +358,7 @@ $(BOOKTABLE , Default precision is large enough to add all digits of the integral value. - In case of ($B 'a') and $(B 'A'), the integral digit can be + In case of $(B 'a') and $(B 'A'), the integral digit can be any hexadecimal digit. ) ) diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d index 6e94a5d..9dcec89 100644 --- a/libphobos/src/std/json.d +++ b/libphobos/src/std/json.d @@ -13,7 +13,7 @@ also $(LINK https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org).) Copyright: Copyright Jeremie Pelletier 2008 - 2009. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jeremie Pelletier, David Herberth -References: $(LINK http://json.org/), $(LINK http://seriot.ch/parsing_json.html) +References: $(LINK http://json.org/), $(LINK https://seriot.ch/projects/parsing_json.html) Source: $(PHOBOSSRC std/json.d) */ /* @@ -804,7 +804,22 @@ struct JSONValue assert(j["author"].str == "Walter"); } - /// + /** + * Compare two JSONValues for equality + * + * JSON arrays and objects are compared deeply. The order of object keys does not matter. + * + * Floating point numbers are compared for exact equality, not approximal equality. + * + * Different number types (unsigned, signed, and floating) will be compared by converting + * them to a common type, in the same way that comparison of built-in D `int`, `uint` and + * `float` works. + * + * Other than that, types must match exactly. + * Empty arrays are not equal to empty objects, and booleans are never equal to integers. + * + * Returns: whether this `JSONValue` is equal to `rhs` + */ bool opEquals(const JSONValue rhs) const @nogc nothrow pure @safe { return opEquals(rhs); @@ -871,9 +886,13 @@ struct JSONValue /// @safe unittest { - assert(JSONValue(0u) == JSONValue(0)); - assert(JSONValue(0u) == JSONValue(0.0)); - assert(JSONValue(0) == JSONValue(0.0)); + assert(JSONValue(10).opEquals(JSONValue(10.0))); + assert(JSONValue(10) != (JSONValue(10.5))); + + assert(JSONValue(1) != JSONValue(true)); + assert(JSONValue.emptyArray != JSONValue.emptyObject); + + assert(parseJSON(`{"a": 1, "b": 2}`).opEquals(parseJSON(`{"b": 2, "a": 1}`))); } /// Implements the foreach `opApply` interface for json arrays. diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d index 8fcd88f..7a72f42 100644 --- a/libphobos/src/std/math/exponential.d +++ b/libphobos/src/std/math/exponential.d @@ -422,217 +422,7 @@ if (isIntegral!I && isFloatingPoint!F) Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow if (isFloatingPoint!(F) && isFloatingPoint!(G)) { - import core.math : fabs, sqrt; - import std.math.traits : isInfinity, isNaN, signbit; - - alias Float = typeof(return); - - static real impl(real x, real y) @nogc pure nothrow - { - // Special cases. - if (isNaN(y)) - return y; - if (isNaN(x) && y != 0.0) - return x; - - // Even if x is NaN. - if (y == 0.0) - return 1.0; - if (y == 1.0) - return x; - - if (isInfinity(y)) - { - if (isInfinity(x)) - { - if (!signbit(y) && !signbit(x)) - return F.infinity; - else - return F.nan; - } - else if (fabs(x) > 1) - { - if (signbit(y)) - return +0.0; - else - return F.infinity; - } - else if (fabs(x) == 1) - { - return F.nan; - } - else // < 1 - { - if (signbit(y)) - return F.infinity; - else - return +0.0; - } - } - if (isInfinity(x)) - { - if (signbit(x)) - { - long i = cast(long) y; - if (y > 0.0) - { - if (i == y && i & 1) - return -F.infinity; - else if (i == y) - return F.infinity; - else - return -F.nan; - } - else if (y < 0.0) - { - if (i == y && i & 1) - return -0.0; - else if (i == y) - return +0.0; - else - return F.nan; - } - } - else - { - if (y > 0.0) - return F.infinity; - else if (y < 0.0) - return +0.0; - } - } - - if (x == 0.0) - { - if (signbit(x)) - { - long i = cast(long) y; - if (y > 0.0) - { - if (i == y && i & 1) - return -0.0; - else - return +0.0; - } - else if (y < 0.0) - { - if (i == y && i & 1) - return -F.infinity; - else - return F.infinity; - } - } - else - { - if (y > 0.0) - return +0.0; - else if (y < 0.0) - return F.infinity; - } - } - if (x == 1.0) - return 1.0; - - if (y >= F.max) - { - if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) - return 0.0; - if (x > 1.0 || x < -1.0) - return F.infinity; - } - if (y <= -F.max) - { - if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) - return F.infinity; - if (x > 1.0 || x < -1.0) - return 0.0; - } - - if (x >= F.max) - { - if (y > 0.0) - return F.infinity; - else - return 0.0; - } - if (x <= -F.max) - { - long i = cast(long) y; - if (y > 0.0) - { - if (i == y && i & 1) - return -F.infinity; - else - return F.infinity; - } - else if (y < 0.0) - { - if (i == y && i & 1) - return -0.0; - else - return +0.0; - } - } - - // Integer power of x. - long iy = cast(long) y; - if (iy == y && fabs(y) < 32_768.0) - return pow(x, iy); - - real sign = 1.0; - if (x < 0) - { - // Result is real only if y is an integer - // Check for a non-zero fractional part - enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L; - static if (maxOdd > ulong.max) - { - // Generic method, for any FP type - import std.math.rounding : floor; - if (floor(y) != y) - return sqrt(x); // Complex result -- create a NaN - - const hy = 0.5 * y; - if (floor(hy) != hy) - sign = -1.0; - } - else - { - // Much faster, if ulong has enough precision - const absY = fabs(y); - if (absY <= maxOdd) - { - const uy = cast(ulong) absY; - if (uy != absY) - return sqrt(x); // Complex result -- create a NaN - - if (uy & 1) - sign = -1.0; - } - } - x = -x; - } - version (INLINE_YL2X) - { - // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) - // TODO: This is not accurate in practice. A fast and accurate - // (though complicated) method is described in: - // "An efficient rounding boundary test for pow(x, y) - // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). - return sign * exp2( core.math.yl2x(x, y) ); - } - else - { - // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) - // TODO: This is not accurate in practice. A fast and accurate - // (though complicated) method is described in: - // "An efficient rounding boundary test for pow(x, y) - // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). - Float w = exp2(y * log2(x)); - return sign * w; - } - } - return impl(x, y); + return _powImpl(x, y); } /// @@ -802,6 +592,216 @@ if (isFloatingPoint!(F) && isFloatingPoint!(G)) assert(pow(-real.infinity, 0.0) == 1.0); } +private real _powImpl(real x, real y) @safe @nogc pure nothrow +{ + alias F = real; + import core.math : fabs, sqrt; + import std.math.traits : isInfinity, isNaN, signbit; + + // Special cases. + if (isNaN(y)) + return y; + if (isNaN(x) && y != 0.0) + return x; + + // Even if x is NaN. + if (y == 0.0) + return 1.0; + if (y == 1.0) + return x; + + if (isInfinity(y)) + { + if (isInfinity(x)) + { + if (!signbit(y) && !signbit(x)) + return F.infinity; + else + return F.nan; + } + else if (fabs(x) > 1) + { + if (signbit(y)) + return +0.0; + else + return F.infinity; + } + else if (fabs(x) == 1) + { + return F.nan; + } + else // < 1 + { + if (signbit(y)) + return F.infinity; + else + return +0.0; + } + } + if (isInfinity(x)) + { + if (signbit(x)) + { + long i = cast(long) y; + if (y > 0.0) + { + if (i == y && i & 1) + return -F.infinity; + else if (i == y) + return F.infinity; + else + return -F.nan; + } + else if (y < 0.0) + { + if (i == y && i & 1) + return -0.0; + else if (i == y) + return +0.0; + else + return F.nan; + } + } + else + { + if (y > 0.0) + return F.infinity; + else if (y < 0.0) + return +0.0; + } + } + + if (x == 0.0) + { + if (signbit(x)) + { + long i = cast(long) y; + if (y > 0.0) + { + if (i == y && i & 1) + return -0.0; + else + return +0.0; + } + else if (y < 0.0) + { + if (i == y && i & 1) + return -F.infinity; + else + return F.infinity; + } + } + else + { + if (y > 0.0) + return +0.0; + else if (y < 0.0) + return F.infinity; + } + } + if (x == 1.0) + return 1.0; + + if (y >= F.max) + { + if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) + return 0.0; + if (x > 1.0 || x < -1.0) + return F.infinity; + } + if (y <= -F.max) + { + if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) + return F.infinity; + if (x > 1.0 || x < -1.0) + return 0.0; + } + + if (x >= F.max) + { + if (y > 0.0) + return F.infinity; + else + return 0.0; + } + if (x <= -F.max) + { + long i = cast(long) y; + if (y > 0.0) + { + if (i == y && i & 1) + return -F.infinity; + else + return F.infinity; + } + else if (y < 0.0) + { + if (i == y && i & 1) + return -0.0; + else + return +0.0; + } + } + + // Integer power of x. + long iy = cast(long) y; + if (iy == y && fabs(y) < 32_768.0) + return pow(x, iy); + + real sign = 1.0; + if (x < 0) + { + // Result is real only if y is an integer + // Check for a non-zero fractional part + enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L; + static if (maxOdd > ulong.max) + { + // Generic method, for any FP type + import std.math.rounding : floor; + if (floor(y) != y) + return sqrt(x); // Complex result -- create a NaN + + const hy = 0.5 * y; + if (floor(hy) != hy) + sign = -1.0; + } + else + { + // Much faster, if ulong has enough precision + const absY = fabs(y); + if (absY <= maxOdd) + { + const uy = cast(ulong) absY; + if (uy != absY) + return sqrt(x); // Complex result -- create a NaN + + if (uy & 1) + sign = -1.0; + } + } + x = -x; + } + version (INLINE_YL2X) + { + // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) + // TODO: This is not accurate in practice. A fast and accurate + // (though complicated) method is described in: + // "An efficient rounding boundary test for pow(x, y) + // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). + return sign * exp2( core.math.yl2x(x, y) ); + } + else + { + // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) + // TODO: This is not accurate in practice. A fast and accurate + // (though complicated) method is described in: + // "An efficient rounding boundary test for pow(x, y) + // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). + auto w = exp2(y * log2(x)); + return sign * w; + } +} + /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`. * * Params: diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d index 648b70e..9f0fb56 100644 --- a/libphobos/src/std/numeric.d +++ b/libphobos/src/std/numeric.d @@ -3405,7 +3405,7 @@ private: // This algorithm works by performing the even and odd parts of our FFT // using the "two for the price of one" method mentioned at - // http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521 + // https://web.archive.org/web/20180312110051/http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521 // by making the odd terms into the imaginary components of our new FFT, // and then using symmetry to recombine them. void fftImplPureReal(Ret, R)(R range, Ret buf) const diff --git a/libphobos/src/std/outbuffer.d b/libphobos/src/std/outbuffer.d index 92af9a9..f6d4ba8 100644 --- a/libphobos/src/std/outbuffer.d +++ b/libphobos/src/std/outbuffer.d @@ -22,9 +22,10 @@ import std.traits : isSomeString; * OutBuffer's byte order is the format native to the computer. * To control the byte order (endianness), use a class derived * from OutBuffer. + * * OutBuffer's internal buffer is allocated with the GC. Pointers * stored into the buffer are scanned by the GC, but you have to - * ensure proper alignment, e.g. by using alignSize((void*).sizeof). + * ensure proper alignment, e.g. by using `alignSize((void*).sizeof)`. */ class OutBuffer @@ -297,7 +298,7 @@ class OutBuffer * Append output of C's vprintf() to internal buffer. */ - void vprintf(scope string format, va_list args) @trusted nothrow + void vprintf(scope string format, va_list args) @system nothrow { import core.stdc.stdio : vsnprintf; import core.stdc.stdlib : alloca; @@ -342,7 +343,7 @@ class OutBuffer * Append output of C's printf() to internal buffer. */ - void printf(scope string format, ...) @trusted + void printf(scope string format, ...) @system { va_list ap; va_start(ap, format); @@ -475,7 +476,7 @@ class OutBuffer buf.write("hello"); buf.write(cast(byte) 0x20); buf.write("world"); - buf.printf(" %d", 62665); + buf.writef(" %d", 62665); assert(cmp(buf.toString(), "hello world 62665") == 0); buf.clear(); diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d index fadb4c1..7525d9b 100644 --- a/libphobos/src/std/parallelism.d +++ b/libphobos/src/std/parallelism.d @@ -884,11 +884,26 @@ identical to the non-@safe case, but safety introduces some restrictions: */ @trusted auto task(F, Args...)(F fun, Args args) -if (is(typeof(fun(args))) && isSafeTask!F) +if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F) { return new Task!(run, F, Args)(fun, args); } +@safe unittest +{ + static struct Oops { + int convert() { + *cast(int*) 0xcafebabe = 0xdeadbeef; + return 0; + } + alias convert this; + } + static void foo(int) @safe {} + + static assert(!__traits(compiles, task(&foo, Oops.init))); + static assert(!__traits(compiles, scopedTask(&foo, Oops.init))); +} + /** These functions allow the creation of `Task` objects on the stack rather than the GC heap. The lifetime of a `Task` created by `scopedTask` @@ -928,7 +943,7 @@ if (is(typeof(delegateOrFp(args))) && !isSafeTask!F) /// Ditto @trusted auto scopedTask(F, Args...)(F fun, Args args) -if (is(typeof(fun(args))) && isSafeTask!F) +if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F) { auto ret = Task!(run, F, Args)(fun, args); ret.isScoped = true; diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d index b6fddf7..e2a2d7d 100644 --- a/libphobos/src/std/range/package.d +++ b/libphobos/src/std/range/package.d @@ -6070,10 +6070,13 @@ nothrow pure @system unittest Generate lockstep's opApply function as a mixin string. If withIndex is true prepend a size_t index to the delegate. */ -private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) +private struct LockstepMixin(Ranges...) { + import std.conv : text; import std.format : format; + string name; + string implName; string[] params; string[] emptyChecks; string[] dgArgs; @@ -6081,76 +6084,101 @@ private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) string indexDef; string indexInc; - if (withIndex) +@safe pure: + this(bool withIndex, bool reverse) { - params ~= "size_t"; - dgArgs ~= "index"; - if (reverse) + if (withIndex) { - indexDef = q{ - size_t index = ranges[0].length-1; - enforce(_stoppingPolicy == StoppingPolicy.requireSameLength, - "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength"); + params ~= "size_t"; + dgArgs ~= "index"; + if (reverse) + { + indexDef = q{ + size_t index = ranges[0].length - 1; + enforce(this.stoppingPolicy == StoppingPolicy.requireSameLength, + "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength"); - foreach (range; ranges[1..$]) - enforce(range.length == ranges[0].length); - }; - indexInc = "--index;"; + foreach (range; ranges[1 .. $]) + enforce(range.length == ranges[0].length); + }; + indexInc = "--index;"; + } + else + { + indexDef = "size_t index = 0;"; + indexInc = "++index;"; + } } - else + + foreach (idx, Range; Ranges) { - indexDef = "size_t index = 0;"; - indexInc = "++index;"; + params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); + emptyChecks ~= format("!ranges[%s].empty", idx); + if (reverse) + { + dgArgs ~= format("ranges[%s].back", idx); + popFronts ~= format("ranges[%s].popBack();", idx); + } + else + { + dgArgs ~= format("ranges[%s].front", idx); + popFronts ~= format("ranges[%s].popFront();", idx); + } } - } - foreach (idx, Range; Ranges) - { - params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); - emptyChecks ~= format("!ranges[%s].empty", idx); if (reverse) { - dgArgs ~= format("ranges[%s].back", idx); - popFronts ~= format("ranges[%s].popBack();", idx); + name = "opApplyReverse"; + if (withIndex) implName = "opApplyReverseIdxImpl"; + else implName = "opApplyReverseImpl"; } else { - dgArgs ~= format("ranges[%s].front", idx); - popFronts ~= format("ranges[%s].popFront();", idx); + name = "opApply"; + if (withIndex) implName = "opApplyIdxImpl"; + else implName = "opApplyImpl"; } } - string name = reverse ? "opApplyReverse" : "opApply"; - - return format( - q{ - int %s(scope int delegate(%s) dg) - { - import std.exception : enforce; - - auto ranges = _ranges; - int res; - %s +const: + string getAlias() + { + return format(q{ + alias %s = %s!(int delegate(%-(%s%|, %))); + }, + name, implName, params + ); + } - while (%s) + string getImpl() + { + return format(q{ + int %s(DG)(scope DG dg) scope { - res = dg(%s); - if (res) break; - %s + import std.exception : enforce; + + auto ranges = this.ranges; %s - } - if (_stoppingPolicy == StoppingPolicy.requireSameLength) - { - foreach (range; ranges) - enforce(range.empty); + while (%-(%s%| && %)) + { + if (int result = dg(%-(%s%|, %))) return result; + %-(%s%| + %) + %s + } + + if (this.stoppingPolicy == StoppingPolicy.requireSameLength) + { + foreach (range; ranges) + enforce(range.empty); + } + return 0; } - return res; - } - }, name, params.join(", "), indexDef, - emptyChecks.join(" && "), dgArgs.join(", "), - popFronts.join("\n "), - indexInc); + }, + implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc + ); + } } /** @@ -6170,10 +6198,6 @@ private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) By default `StoppingPolicy` is set to `StoppingPolicy.shortest`. - Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be - inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to - a different implementation. - See_Also: $(LREF zip) `lockstep` is similar to $(LREF zip), but `zip` bundles its @@ -6184,41 +6208,53 @@ private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) { + private Ranges ranges; + private StoppingPolicy stoppingPolicy; + /// - this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest) + this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest) { import std.exception : enforce; - _ranges = ranges; + this.ranges = ranges; enforce(sp != StoppingPolicy.longest, - "Can't use StoppingPolicy.Longest on Lockstep."); - _stoppingPolicy = sp; + "Can't use StoppingPolicy.Longest on Lockstep."); + this.stoppingPolicy = sp; } - mixin(lockstepMixin!Ranges(false, false)); - mixin(lockstepMixin!Ranges(true, false)); + private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false); + mixin(lockstepMixinFF.getImpl); + + private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false); + mixin(lockstepMixinTF.getImpl); + + mixin(lockstepMixinFF.getAlias); + mixin(lockstepMixinTF.getAlias); + static if (allSatisfy!(isBidirectionalRange, Ranges)) { - mixin(lockstepMixin!Ranges(false, true)); + private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true); + mixin(lockstepMixinFT.getImpl); static if (allSatisfy!(hasLength, Ranges)) { - mixin(lockstepMixin!Ranges(true, true)); + private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true); + mixin(lockstepMixinTT.getImpl); + mixin(lockstepMixinTT.getAlias); } else { - mixin(lockstepReverseFailMixin!Ranges(true)); + mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); + alias opApplyReverse = opApplyReverseIdxFail; } + mixin(lockstepMixinFT.getAlias); } else { - mixin(lockstepReverseFailMixin!Ranges(false)); - mixin(lockstepReverseFailMixin!Ranges(true)); + mixin(lockstepReverseFailMixin!Ranges(withIndex: false)); + mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); + alias opApplyReverse = opApplyReverseFail; + alias opApplyReverse = opApplyReverseIdxFail; } - -private: - alias R = Ranges; - R _ranges; - StoppingPolicy _stoppingPolicy; } /// Ditto @@ -6238,33 +6274,39 @@ if (allSatisfy!(isInputRange, Ranges)) } /// -@system unittest +pure @safe unittest { - auto arr1 = [1,2,3,4,5,100]; - auto arr2 = [6,7,8,9,10]; + int[6] arr1 = [1,2,3,4,5,100]; + int[5] arr2 = [6,7,8,9,10]; - foreach (ref a, b; lockstep(arr1, arr2)) - { - a += b; - } + foreach (ref a, b; lockstep(arr1[], arr2[])) + { + a += b; + } - assert(arr1 == [7,9,11,13,15,100]); + assert(arr1 == [7,9,11,13,15,100]); +} - /// Lockstep also supports iterating with an index variable: - foreach (index, a, b; lockstep(arr1, arr2)) - { - assert(arr1[index] == a); - assert(arr2[index] == b); - } +/// Lockstep also supports iterating with an index variable: +pure @safe unittest +{ + int[3] arr1 = [1,2,3]; + int[3] arr2 = [4,5,6]; + + foreach (index, a, b; lockstep(arr1[], arr2[])) + { + assert(arr1[index] == a); + assert(arr2[index] == b); + } } // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep -@system unittest +pure @safe unittest { auto arr1 = [0, 1, 2, 3]; auto arr2 = [4, 5, 6, 7]; - size_t n = arr1.length -1; + size_t n = arr1.length - 1; foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength)) { assert(n == index); @@ -6283,7 +6325,7 @@ if (allSatisfy!(isInputRange, Ranges)) } } -@system unittest +pure @safe unittest { import std.algorithm.iteration : filter; import std.conv : to; @@ -6380,7 +6422,7 @@ if (allSatisfy!(isInputRange, Ranges)) foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } } -@system unittest +pure @safe unittest { struct RvalueRange { @@ -6436,11 +6478,11 @@ private string lockstepReverseFailMixin(Ranges...)(bool withIndex) return format( q{ - int opApplyReverse()(scope int delegate(%s) dg) + int opApplyReverse%sFail()(scope int delegate(%s) dg) { static assert(false, "%s"); } - }, params.join(", "), message); + }, withIndex ? "Idx" : "" , params.join(", "), message); } // For generic programming, make sure Lockstep!(Range) is well defined for a diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index 8caa9b3..b474460 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -220,31 +220,6 @@ version (CRuntime_Microsoft) private alias _FGETWC = _fgetwc_nolock; private alias _FLOCK = _lock_file; private alias _FUNLOCK = _unlock_file; - - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTC = _fputc_nolock; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTWC = _fputwc_nolock; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETC = _fgetc_nolock; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETWC = _fgetwc_nolock; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FLOCK = _lock_file; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FUNLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FUNLOCK = _unlock_file; } else version (CRuntime_Glibc) { @@ -254,31 +229,6 @@ else version (CRuntime_Glibc) private alias _FGETWC = fgetwc_unlocked; private alias _FLOCK = core.sys.posix.stdio.flockfile; private alias _FUNLOCK = core.sys.posix.stdio.funlockfile; - - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTC = fputc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTWC = fputwc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETC = fgetc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETWC = fgetwc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FLOCK = core.sys.posix.stdio.flockfile; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FUNLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FUNLOCK = core.sys.posix.stdio.funlockfile; } else version (GENERIC_IO) { @@ -304,52 +254,6 @@ else version (GENERIC_IO) { static assert(0, "don't know how to lock files on GENERIC_IO"); } - - // @@@DEPRECATED_2.107@@@ - deprecated("internal function fputc_unlocked was unintentionally available " - ~ "from std.stdio and will be removed afer 2.107") - extern (C) pragma(mangle, fputc.mangleof) int fputc_unlocked(int c, _iobuf* fp); - // @@@DEPRECATED_2.107@@@ - deprecated("internal function fputwc_unlocked was unintentionally available " - ~ "from std.stdio and will be removed afer 2.107") - extern (C) pragma(mangle, core.stdc.wchar_.fputwc.mangleof) int fputwc_unlocked(wchar_t c, _iobuf* fp); - // @@@DEPRECATED_2.107@@@ - deprecated("internal function fgetc_unlocked was unintentionally available " - ~ "from std.stdio and will be removed afer 2.107") - extern (C) pragma(mangle, fgetc.mangleof) int fgetc_unlocked(_iobuf* fp); - // @@@DEPRECATED_2.107@@@ - deprecated("internal function fgetwc_unlocked was unintentionally available " - ~ "from std.stdio and will be removed afer 2.107") - extern (C) pragma(mangle, core.stdc.wchar_.fgetwc.mangleof) int fgetwc_unlocked(_iobuf* fp); - - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTC = fputc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FPUTWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FPUTWC = fputwc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETC = fgetc_unlocked; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FGETWC was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FGETWC = fgetwc_unlocked; - - version (Posix) - { - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FLOCK = core.sys.posix.stdio.flockfile; - // @@@DEPRECATED_2.107@@@ - deprecated("internal alias FUNLOCK was unintentionally available from " - ~ "std.stdio and will be removed afer 2.107") - alias FUNLOCK = core.sys.posix.stdio.funlockfile; - } } else { @@ -795,7 +699,7 @@ Throws: `ErrnoException` in case of error. /** Detaches from the current file (throwing on failure), and then runs a command by calling the C standard library function $(HTTP -opengroup.org/onlinepubs/007908799/xsh/_popen.html, _popen). +pubs.opengroup.org/onlinepubs/7908799/xsh/popen.html, popen). Throws: `ErrnoException` in case of error. */ @@ -813,8 +717,9 @@ The mode must be compatible with the mode of the file descriptor. Throws: `ErrnoException` in case of error. Params: fd = File descriptor to associate with this `File`. - stdioOpenmode = Mode to associate with this File. The mode has the same semantics - semantics as in the C standard library $(CSTDIO fdopen) function, + stdioOpenmode = Mode to associate with this File. The mode has the same + semantics as in the POSIX library function $(HTTP + pubs.opengroup.org/onlinepubs/7908799/xsh/fdopen.html, fdopen) and must be compatible with `fd`. */ void fdopen(int fd, scope const(char)[] stdioOpenmode = "rb") @safe @@ -1135,6 +1040,9 @@ Throws: `ErrnoException` if the file is not opened or the call to `fread` fails. assert(buf == "\r\n\n\r\n"); } + // https://issues.dlang.org/show_bug.cgi?id=24685 + static assert(!__traits(compiles, (File f) @safe { int*[1] bar; f.rawRead(bar[]); })); + // https://issues.dlang.org/show_bug.cgi?id=21729 @system unittest { @@ -4576,11 +4484,11 @@ if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) && { /* * The new opengroup large file support API is transparently - * included in the normal C bindings. http://opengroup.org/platform/lfs.html#1.0 + * included in the normal C bindings. https://www.opengroup.org/platform/lfs.html#1.0 * if _FILE_OFFSET_BITS in druntime is 64, off_t is 64 bit and * the normal functions work fine. If not, then large file support * probably isn't available. Do not use the old transitional API - * (the native extern(C) fopen64, http://www.unix.org/version2/whatsnew/lfs20mar.html#3.0) + * (the native extern(C) fopen64, https://unix.org/version2/whatsnew/lfs20mar.html#3.0) */ import core.sys.posix.stdio : fopen; return fopen(namez, modez); @@ -4629,6 +4537,13 @@ private auto trustedFwrite(T)(FILE* f, const T[] obj) @trusted * Convenience function that forwards to `core.stdc.stdio.fread` */ private auto trustedFread(T)(FILE* f, T[] obj) @trusted +if (!imported!"std.traits".hasIndirections!T) +{ + return fread(obj.ptr, T.sizeof, obj.length, f); +} + +private auto trustedFread(T)(FILE* f, T[] obj) @system +if (imported!"std.traits".hasIndirections!T) { return fread(obj.ptr, T.sizeof, obj.length, f); } diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 3c425c7..aceb287 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -3544,6 +3544,35 @@ struct Nullable(T) } /** + * Returns true if `this` has a value, otherwise false. + * + * Allows a `Nullable` to be used as the condition in an `if` statement: + * + * --- + * if (auto result = functionReturningNullable()) + * { + * doSomethingWith(result.get); + * } + * --- + */ + bool opCast(T : bool)() const + { + return !isNull; + } + + /// Prevents `opCast` from disabling built-in conversions. + auto ref T opCast(T, this This)() + if (is(This : T) || This.sizeof == T.sizeof) + { + static if (is(This : T)) + // Convert implicitly + return this; + else + // Reinterpret + return *cast(T*) &this; + } + + /** * Forces `this` to the null state. */ void nullify()() @@ -4400,6 +4429,26 @@ auto nullable(T)(T t) assert(destroyed); } +// https://issues.dlang.org/show_bug.cgi?id=22293 +@safe unittest +{ + Nullable!int empty; + Nullable!int full = 123; + + assert(cast(bool) empty == false); + assert(cast(bool) full == true); + + if (empty) assert(0); + if (!full) assert(0); +} + +// check that opCast doesn't break unsafe casts +@system unittest +{ + Nullable!(const(int*)) a; + auto result = cast(immutable(Nullable!(int*))) a; +} + /** Just like `Nullable!T`, except that the null state is defined as a particular value. For example, $(D Nullable!(uint, uint.max)) is an @@ -10928,19 +10977,22 @@ struct RefCounted(T, RefCountedAutoInitialize autoInit = swap(_refCounted._store, rhs._refCounted._store); } - void opAssign(T rhs) + static if (__traits(compiles, lvalueOf!T = T.init)) { - import std.algorithm.mutation : move; - - static if (autoInit == RefCountedAutoInitialize.yes) + void opAssign(T rhs) { - _refCounted.ensureInitialized(); - } - else - { - assert(_refCounted.isInitialized); + import std.algorithm.mutation : move; + + static if (autoInit == RefCountedAutoInitialize.yes) + { + _refCounted.ensureInitialized(); + } + else + { + assert(_refCounted.isInitialized); + } + move(rhs, _refCounted._store._payload); } - move(rhs, _refCounted._store._payload); } static if (autoInit == RefCountedAutoInitialize.yes) diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index f0d5d4d..9a326a5 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -53,7 +53,7 @@ $(TR $(TD Miscellaneous) $(TD See_Also: $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br> $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br> - $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335) + $(LINK https://web.archive.org/web/20100113043530/https://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335) Copyright: Copyright The D Language Foundation 2000 - 2012. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright) and |