diff options
Diffstat (limited to 'libphobos/src')
32 files changed, 426 insertions, 270 deletions
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index d02f72d..09da6a8 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -3ad507b5125573c5b47736a0913105bfb1249746 +792c8b7c1d5957767e138f78d04bf175d4b92f10 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d index 839183d..9b1d920 100644 --- a/libphobos/src/std/algorithm/mutation.d +++ b/libphobos/src/std/algorithm/mutation.d @@ -573,7 +573,7 @@ $(LINK2 http://en.cppreference.com/w/cpp/algorithm/copy_backward, STL's `copy_ba Assigns `value` to each element of input range `range`. Alternatively, instead of using a single `value` to fill the `range`, -a `filter` $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) +a `filler` $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) can be provided. The length of `filler` and `range` do not need to match, but `filler` must not be empty. diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d index 4fc7ee9..ddb80b8 100644 --- a/libphobos/src/std/algorithm/sorting.d +++ b/libphobos/src/std/algorithm/sorting.d @@ -3946,7 +3946,7 @@ if (isRandomAccessRange!(Range1) && hasLength!Range1 && { foreach (T2; ReferenceRanges) { - import std.array; + import std.array : array; T1 A; T2 B; diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d index 3e88200..daa103a 100644 --- a/libphobos/src/std/array.d +++ b/libphobos/src/std/array.d @@ -169,8 +169,8 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range) } /// ditto -ForeachType!(PointerTarget!Range)[] array(Range)(Range r) -if (isPointer!Range && isIterable!(PointerTarget!Range) && !isAutodecodableString!Range && !isInfinite!Range) +ForeachType!(typeof((*Range).init))[] array(Range)(Range r) +if (is(Range : U*, U) && isIterable!U && !isAutodecodableString!Range && !isInfinite!Range) { return array(*r); } @@ -3416,7 +3416,8 @@ do Implements an output range that appends data to an array. This is recommended over $(D array ~= data) when appending many elements because it is more efficient. `Appender` maintains its own array metadata locally, so it can avoid -global locking for each append where $(LREF capacity) is non-zero. +the $(DDSUBLINK spec/arrays, capacity-reserve, performance hit of looking up slice `capacity`) +for each append. Params: A = the array type to simulate. @@ -3587,7 +3588,7 @@ if (isDynamicArray!A) private template canPutItem(U) { enum bool canPutItem = - isImplicitlyConvertible!(Unqual!U, Unqual!T) || + is(Unqual!U : Unqual!T) || isSomeChar!T && isSomeChar!U; } private template canPutConstRange(Range) diff --git a/libphobos/src/std/base64.d b/libphobos/src/std/base64.d index 2f7213b..0fc92ac 100644 --- a/libphobos/src/std/base64.d +++ b/libphobos/src/std/base64.d @@ -639,7 +639,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') */ void popFront() { - enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining")); + assert(!empty, "Cannot call popFront on Encoder with no data remaining"); range_.popFront(); @@ -757,7 +757,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') */ void popFront() { - enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining")); + assert(!empty, "Cannot call popFront on Encoder with no data remaining"); static if (Padding != NoPadding) if (padding) @@ -1414,7 +1414,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') */ void popFront() { - enforce(!empty, new Base64Exception("Cannot call popFront on Decoder with no data remaining.")); + assert(!empty, "Cannot call popFront on Decoder with no data remaining."); range_.popFront(); diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d index f131257..559f8da 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -1418,9 +1418,9 @@ public: /** Flips a single bit, specified by `pos` */ - void flip(size_t i) @nogc pure nothrow + void flip(size_t pos) @nogc pure nothrow { - bt(_ptr, i) ? btr(_ptr, i) : bts(_ptr, i); + bt(_ptr, pos) ? btr(_ptr, pos) : bts(_ptr, pos); } /// diff --git a/libphobos/src/std/checkedint.d b/libphobos/src/std/checkedint.d index 635c420..79597e8 100644 --- a/libphobos/src/std/checkedint.d +++ b/libphobos/src/std/checkedint.d @@ -630,36 +630,36 @@ if (isIntegral!T || is(T == Checked!(U, H), U, H)) import core.atomic : atomicLoad, MemoryOrder; static if (is(typeof(this.payload.atomicLoad!(MemoryOrder.acq)) P)) { - auto payload = __ctfe ? cast(P) this.payload + auto localPayload = __ctfe ? cast(P) this.payload : this.payload.atomicLoad!(MemoryOrder.acq); } else { - alias payload = this.payload; + alias localPayload = this.payload; } static if (hasMember!(Hook, "hookToHash")) { - return hook.hookToHash(payload); + return hook.hookToHash(localPayload); } else static if (stateSize!Hook > 0) { - static if (hasMember!(typeof(payload), "toHash")) + static if (hasMember!(typeof(localPayload), "toHash")) { - return payload.toHash() ^ hashOf(hook); + return localPayload.toHash() ^ hashOf(hook); } else { - return hashOf(payload) ^ hashOf(hook); + return hashOf(localPayload) ^ hashOf(hook); } } - else static if (hasMember!(typeof(payload), "toHash")) + else static if (hasMember!(typeof(localPayload), "toHash")) { - return payload.toHash(); + return localPayload.toHash(); } else { - return .hashOf(payload); + return .hashOf(localPayload); } } diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d index bc53236..323926a 100644 --- a/libphobos/src/std/concurrency.d +++ b/libphobos/src/std/concurrency.d @@ -480,7 +480,7 @@ private template isSpawnable(F, T...) enum isParamsImplicitlyConvertible = false; else static if (param1.length == i) enum isParamsImplicitlyConvertible = true; - else static if (isImplicitlyConvertible!(param2[i], param1[i])) + else static if (is(param2[i] : param1[i])) enum isParamsImplicitlyConvertible = isParamsImplicitlyConvertible!(F1, F2, i + 1); else @@ -2129,7 +2129,7 @@ private static assert(T.length, "T must not be empty"); - static if (isImplicitlyConvertible!(T[0], Duration)) + static if (is(T[0] : Duration)) { alias Ops = AliasSeq!(T[1 .. $]); alias ops = vals[1 .. $]; diff --git a/libphobos/src/std/container/array.d b/libphobos/src/std/container/array.d index ecc4599..f5efe6d 100644 --- a/libphobos/src/std/container/array.d +++ b/libphobos/src/std/container/array.d @@ -34,7 +34,7 @@ pure @system unittest float[] a0; { import std.range : iota; - import std.array; + import std.array : array; import std.algorithm.iteration : map; a0 = iota (0, n).map!(i => i * 1.1f).array; } @@ -991,7 +991,7 @@ if (!is(immutable T == immutable bool)) */ void removeBack() { - enforce(!empty); + assert(!empty); static if (hasElaborateDestructor!T) .destroy(_data._payload[$ - 1]); @@ -1812,49 +1812,49 @@ if (is(immutable T == immutable bool)) /// Ditto @property T front() { - enforce(!empty, "Attempting to access the front of an empty Array"); + assert(!empty, "Attempting to access the front of an empty Array"); return _outer[_a]; } /// Ditto @property void front(bool value) { - enforce(!empty, "Attempting to set the front of an empty Array"); + assert(!empty, "Attempting to set the front of an empty Array"); _outer[_a] = value; } /// Ditto T moveFront() { - enforce(!empty, "Attempting to move the front of an empty Array"); + assert(!empty, "Attempting to move the front of an empty Array"); return _outer.moveAt(_a); } /// Ditto void popFront() { - enforce(!empty, "Attempting to popFront an empty Array"); + assert(!empty, "Attempting to popFront an empty Array"); ++_a; } /// Ditto @property T back() { - enforce(!empty, "Attempting to access the back of an empty Array"); + assert(!empty, "Attempting to access the back of an empty Array"); return _outer[_b - 1]; } /// Ditto @property void back(bool value) { - enforce(!empty, "Attempting to set the back of an empty Array"); + assert(!empty, "Attempting to set the back of an empty Array"); _outer[_b - 1] = value; } /// Ditto T moveBack() { - enforce(!empty, "Attempting to move the back of an empty Array"); + assert(!empty, "Attempting to move the back of an empty Array"); return _outer.moveAt(_b - 1); } /// Ditto void popBack() { - enforce(!empty, "Attempting to popBack an empty Array"); + assert(!empty, "Attempting to popBack an empty Array"); --_b; } /// Ditto @@ -2029,14 +2029,14 @@ if (is(immutable T == immutable bool)) */ @property bool front() { - enforce(!empty); + assert(!empty); return data.ptr[0] & 1; } /// Ditto @property void front(bool value) { - enforce(!empty); + assert(!empty); if (value) data.ptr[0] |= 1; else data.ptr[0] &= ~cast(size_t) 1; } @@ -2052,14 +2052,14 @@ if (is(immutable T == immutable bool)) */ @property bool back() { - enforce(!empty); + assert(!empty); return cast(bool)(data.back & (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord))); } /// Ditto @property void back(bool value) { - enforce(!empty); + assert(!empty); if (value) { data.back |= (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord)); diff --git a/libphobos/src/std/container/binaryheap.d b/libphobos/src/std/container/binaryheap.d index 723630c..7ff14fc 100644 --- a/libphobos/src/std/container/binaryheap.d +++ b/libphobos/src/std/container/binaryheap.d @@ -249,7 +249,7 @@ according to `less`. */ @property ElementType!Store front() { - enforce(!empty, "Cannot call front on an empty heap."); + assert(!empty, "Cannot call front on an empty heap."); return _store.front; } @@ -317,7 +317,7 @@ Removes the largest element from the heap. */ void removeFront() { - enforce(!empty, "Cannot call removeFront on an empty heap."); + assert(!empty, "Cannot call removeFront on an empty heap."); if (_length > 1) { auto t1 = _store[].moveFront(); diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 0f66065..d1b6421 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -162,12 +162,12 @@ private template isEnumStrToStr(S, T) { - enum isEnumStrToStr = isImplicitlyConvertible!(S, T) && + enum isEnumStrToStr = is(S : T) && is(S == enum) && isExactSomeString!T; } template isNullToStr(S, T) { - enum isNullToStr = isImplicitlyConvertible!(S, T) && + enum isNullToStr = is(S : T) && (is(immutable S == immutable typeof(null))) && isExactSomeString!T; } } @@ -542,7 +542,7 @@ If the source type is implicitly convertible to the target type, $(D to) simply performs the implicit conversion. */ private T toImpl(T, S)(S value) -if (isImplicitlyConvertible!(S, T) && +if (is(S : T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) { template isSignedInt(T) @@ -699,7 +699,7 @@ if (isStaticArray!S) When source type supports member template function opCast, it is used. */ private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && is(typeof(S.init.opCast!T()) : T) && !isExactSomeString!T && !is(typeof(T(value)))) @@ -750,7 +750,7 @@ $(UL $(LI If target type is struct, `T(value)` is used.) $(LI If target type is class, $(D new T(value)) is used.)) */ private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && is(T == struct) && is(typeof(T(value)))) { return T(value); @@ -799,7 +799,7 @@ if (!isImplicitlyConvertible!(S, T) && /// ditto private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && is(T == class) && is(typeof(new T(value)))) { return new T(value); @@ -872,7 +872,7 @@ Object-to-object conversions by dynamic casting throw exception when the source non-null and the target is null. */ private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) && (is(T == class) || is(T == interface)) && !is(typeof(new T(value)))) { @@ -957,7 +957,7 @@ if (!isImplicitlyConvertible!(S, T) && alias tgtmod = AddModifier!m2; // Compile time convertible equals to modifier convertible. - static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object)) + static if (is(srcmod!Object : tgtmod!Object)) { // Test runtime conversions: class to class, class to interface, // interface to class, and interface to interface @@ -993,7 +993,7 @@ if (!isImplicitlyConvertible!(S, T) && Handles type _to string conversions */ private T toImpl(T, S)(S value) -if (!(isImplicitlyConvertible!(S, T) && +if (!(is(S : T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) && !isInfinite!S && isExactSomeString!T) { @@ -1138,7 +1138,7 @@ if (!(isImplicitlyConvertible!(S, T) && To string conversion for non copy-able structs */ private T toImpl(T, S)(ref S value) -if (!(isImplicitlyConvertible!(S, T) && +if (!(is(S : T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) && !isInfinite!S && isExactSomeString!T && !isCopyable!S && !isStaticArray!S) { @@ -1528,7 +1528,7 @@ Narrowing numeric-numeric conversions throw when the value does not fit in the narrower type. */ private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && (isNumeric!S || isSomeChar!S || isBoolean!S) && (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum)) { @@ -1643,7 +1643,7 @@ Array-to-array conversion (except when target is a string type) converts each element in turn by using `to`. */ private T toImpl(T, S)(scope S value) -if (!isImplicitlyConvertible!(S, T) && +if (!is(S : T) && !isSomeString!S && isDynamicArray!S && !isExactSomeString!T && isArray!T) { @@ -1725,7 +1725,7 @@ Associative array to associative array conversion converts each key and each value in turn. */ private T toImpl(T, S)(S value) -if (!isImplicitlyConvertible!(S, T) && isAssociativeArray!S && +if (!is(S : T) && isAssociativeArray!S && isAssociativeArray!T && !is(T == enum)) { /* This code is potentially unsafe. diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d index e80f122..6898934 100644 --- a/libphobos/src/std/datetime/systime.d +++ b/libphobos/src/std/datetime/systime.d @@ -10095,7 +10095,7 @@ else version (Windows) static void testScope(scope ref SysTime st) @safe { - auto result = SysTimeToSYSTEMTIME(st); + auto localResult = SysTimeToSYSTEMTIME(st); } } @@ -10178,7 +10178,7 @@ else version (Windows) static void testScope(scope ref SysTime st) @safe { - auto result = SysTimeToFILETIME(st); + auto local_result = SysTimeToFILETIME(st); } } } diff --git a/libphobos/src/std/digest/hmac.d b/libphobos/src/std/digest/hmac.d index 6864fc3..6688ba7 100644 --- a/libphobos/src/std/digest/hmac.d +++ b/libphobos/src/std/digest/hmac.d @@ -202,14 +202,14 @@ if (hashBlockSize % 8 == 0) import std.string : representation; string data1 = "Hello, world", data2 = "Hola mundo"; auto hmac = HMAC!SHA1("My s3cR3T keY".representation); - auto digest = hmac.put(data1.representation) + auto testDigest = hmac.put(data1.representation) .put(data2.representation) .finish(); static immutable expected = [ 197, 57, 52, 3, 13, 194, 13, 36, 117, 228, 8, 11, 111, 51, 165, 3, 123, 31, 251, 113]; - assert(digest == expected); + assert(testDigest == expected); } } diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d index 129c05d..b699a8e 100644 --- a/libphobos/src/std/exception.d +++ b/libphobos/src/std/exception.d @@ -1069,9 +1069,9 @@ as the language is free to assume objects don't have internal pointers */ bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow if (__traits(isRef, source) || isDynamicArray!S || - isPointer!S || is(S == class)) + is(S : U*, U) || is(S == class)) { - static if (isPointer!S || is(S == class) || is(S == interface)) + static if (is(S : U*, U) || is(S == class) || is(S == interface)) { const m = *cast(void**) &source; const b = cast(void*) ⌖ @@ -1115,9 +1115,9 @@ bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target /// ditto bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow if (__traits(isRef, source) || isDynamicArray!S || - isPointer!S || is(S == class)) + is(S : U*, U) || is(S == class)) { - static if (isPointer!S || is(S == class) || is(S == interface)) + static if (is(S : U*, U) || is(S == class) || is(S == interface)) { const m = *cast(void**) &source; const b = cast(void*) ⌖ diff --git a/libphobos/src/std/experimental/allocator/building_blocks/package.d b/libphobos/src/std/experimental/allocator/building_blocks/package.d index 962ed91..6bc527d 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/package.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/package.d @@ -147,7 +147,11 @@ Sizes through 3584 bytes are handled via freelists of staggered sizes. Sizes from 3585 bytes through 4072 KB are handled by a `BitmappedBlock` with a block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`. ----- +$(RUNNABLE_EXAMPLE + ---- + import std.experimental.allocator; + import std.algorithm.comparison : max; + alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), @@ -157,8 +161,7 @@ block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`. 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), - 4072 * 1024, AllocatorList!( - () => BitmappedBlock!(GCAllocator, 4096)(4072 * 1024)), + 4072 * 1024, AllocatorList!(n => Region!GCAllocator(max(n, 1024 * 4096))), GCAllocator ); A tuMalloc; @@ -169,7 +172,8 @@ block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`. assert(tuMalloc.expand(c, 14)); tuMalloc.deallocate(b); tuMalloc.deallocate(c); ----- + ---- +) $(H2 Allocating memory for sharing across threads) diff --git a/libphobos/src/std/experimental/allocator/package.d b/libphobos/src/std/experimental/allocator/package.d index 2177926..7dbc47a 100644 --- a/libphobos/src/std/experimental/allocator/package.d +++ b/libphobos/src/std/experimental/allocator/package.d @@ -27,13 +27,22 @@ $(TR $(TD Global) $(TD $(LREF theAllocator) )) $(TR $(TD Class interface) $(TD - $(LREF allocatorObject) $(LREF CAllocatorImpl) + $(LREF CSharedAllocatorImpl) $(LREF IAllocator) + $(LREF ISharedAllocator) +)) +$(TR $(TD Structs) $(TD + $(LREF allocatorObject) + $(LREF RCIAllocator) + $(LREF RCISharedAllocator) + $(LREF sharedAllocatorObject) + $(LREF ThreadLocal) )) ) Synopsis: +$(RUNNABLE_EXAMPLE --- // Allocate an int, initialize it with 42 int* p = theAllocator.make!int(42); @@ -46,7 +55,10 @@ p = processAllocator.make!int(100); assert(*p == 100); // Destroy and deallocate processAllocator.dispose(p); - +--- +) +$(RUNNABLE_EXAMPLE +--- // Create an array of 50 doubles initialized to -1.0 double[] arr = theAllocator.makeArray!double(50, -1.0); // Append two zeros to it @@ -56,6 +68,7 @@ theAllocator.shrinkArray(arr, 2); // Destroy and deallocate theAllocator.dispose(arr); --- +) $(H2 Layered Structure) diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index 8d1b431..d031096 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -4986,21 +4986,20 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled) { string[] listdir(string pathname) { - import std.algorithm; - import std.array; - import std.file; - import std.path; + import std.algorithm.iteration : map, filter; + import std.array : array; + import std.path : baseName; - return std.file.dirEntries(pathname, SpanMode.shallow) + return dirEntries(pathname, SpanMode.shallow) .filter!(a => a.isFile) - .map!((return a) => std.path.baseName(a.name)) + .map!((return a) => baseName(a.name)) .array; } // Can be safe only with -preview=dip1000 @safe void main(string[] args) { - import std.stdio; + import std.stdio : writefln; string[] files = listdir(args[1]); writefln("%s", files); diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d index 8089cfa..32c82995 100644 --- a/libphobos/src/std/format/internal/write.d +++ b/libphobos/src/std/format/internal/write.d @@ -3011,7 +3011,7 @@ void enforceValidFormatSpec(T, Char)(scope const ref FormatSpec!Char f) /* `enum`s are formatted like their base value */ -void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) val, scope const ref FormatSpec!Char f) +void formatValueImpl(Writer, T, Char)(auto ref Writer w, T val, scope const ref FormatSpec!Char f) if (is(T == enum)) { import std.array : appender; @@ -3020,21 +3020,15 @@ if (is(T == enum)) if (f.spec != 's') return formatValueImpl(w, cast(OriginalType!T) val, f); - static foreach (e; EnumMembers!T) - { - if (val == e) - { - formatValueImpl(w, __traits(identifier, e), f); - return; - } - } + foreach (immutable member; __traits(allMembers, T)) + if (val == __traits(getMember, T, member)) + return formatValueImpl(w, member, f); auto w2 = appender!string(); // val is not a member of T, output cast(T) rawValue instead. - put(w2, "cast("); - put(w2, T.stringof); - put(w2, ")"); + enum prefix = "cast(" ~ T.stringof ~ ")"; + put(w2, prefix); static assert(!is(OriginalType!T == T), "OriginalType!" ~ T.stringof ~ "must not be equal to " ~ T.stringof); @@ -3154,7 +3148,7 @@ if (isPointer!T && !is(T == enum) && !hasToString!(T, Char)) auto a = iota(0, 10); auto b = iota(0, 10); - auto p = () @trusted { auto p = &a; return p; }(); + auto p = () @trusted { auto result = &a; return result; }(); assert(format("%s",p) != format("%s",b)); } diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d index d83f028..f1d4705 100644 --- a/libphobos/src/std/format/package.d +++ b/libphobos/src/std/format/package.d @@ -212,17 +212,17 @@ There are several flags that affect the outcome of the formatting. $(BOOKTABLE , $(TR $(TH Flag) $(TH Semantics)) $(TR $(TD $(B '-')) - $(TD When the formatted result is shorter then the value - given by the width parameter, the output is right - justified. With the $(B '-') flag this is changed - to left justification. + $(TD When the formatted result is shorter than the value + given by the width parameter, the output is left + justified. Without the $(B '-') flag, the output remains + right justified. There are two exceptions where the $(B '-') flag has a different meaning: (1) with $(B 'r') it denotes to use little endian and (2) in case of a compound indicator it means that no special handling of the members is applied.)) $(TR $(TD $(B '=')) - $(TD When the formatted result is shorter then the value + $(TD When the formatted result is shorter than the value given by the width parameter, the output is centered. If the central position is not possible it is moved slightly to the right. In this case, if $(B '-') flag is present in @@ -1563,6 +1563,14 @@ char[] sformat(Char, Args...)(return scope char[] buf, scope const(Char)[] fmt, { char[] buf; size_t i; + void put(char c) + { + if (buf.length <= i) + throw new RangeError(__FILE__, __LINE__); + + buf[i] = c; + i += 1; + } void put(dchar c) { char[4] enc; @@ -1687,6 +1695,19 @@ if (isSomeString!(typeof(fmt))) assert(u == v); } +@safe unittest // https://issues.dlang.org/show_bug.cgi?id=23488 +{ + static struct R + { + string s = "Ãœ"; + bool empty() { return s.length == 0; } + char front() { return s[0]; } + void popFront() { s = s[1 .. $]; } + } + char[2] buf; + assert(sformat(buf, "%s", R()) == "Ãœ"); +} + version (StdUnittest) private void formatReflectTest(T)(ref T val, string fmt, string formatted, string fn = __FILE__, size_t ln = __LINE__) { diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d index cbab512..2aa45d7 100644 --- a/libphobos/src/std/format/write.d +++ b/libphobos/src/std/format/write.d @@ -1310,3 +1310,23 @@ void formatValue(Writer, T, Char)(auto ref Writer w, auto ref T val, scope const writer.formatValue(a, spec); assert(writer.data == "0"); } + +// https://issues.dlang.org/show_bug.cgi?id=23400 +@safe pure unittest +{ + import std.range : nullSink; + import std.format.spec : singleSpec; + + static struct S + { + // non-const opEquals method + bool opEquals(S rhs) { return false; } + } + + enum E { a = S() } + + E e; + auto writer = nullSink; + const spec = singleSpec("%s"); + writer.formatValue(e, spec); +} diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d index b239901..c85247f 100644 --- a/libphobos/src/std/getopt.d +++ b/libphobos/src/std/getopt.d @@ -558,7 +558,7 @@ private template optionValidator(A...) import std.format : format; enum fmt = "getopt validator: %s (at position %d)"; - enum isReceiver(T) = isPointer!T || (is(T == function)) || (is(T == delegate)); + enum isReceiver(T) = is(T : U*, U) || (is(T == function)) || (is(T == delegate)); enum isOptionStr(T) = isSomeString!T || isSomeChar!T; auto validator() diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d index 40e42da..81c7302 100644 --- a/libphobos/src/std/math/hardware.d +++ b/libphobos/src/std/math/hardware.d @@ -37,13 +37,6 @@ version (RISCV64) version = RISCV_Any; version (D_InlineAsm_X86) version = InlineAsm_X86_Any; version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; -version (InlineAsm_X86_Any) version = InlineAsm_X87; -version (InlineAsm_X87) -{ - static assert(real.mant_dig == 64); - version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC; -} - version (X86_64) version = StaticallyHaveSSE; version (X86) version (OSX) version = StaticallyHaveSSE; @@ -76,19 +69,6 @@ version (D_HardFloat) version (IeeeFlagsSupport) version = FloatingPointControlSupport; } -version (GNU) -{ - // The compiler can unexpectedly rearrange floating point operations and - // access to the floating point status flags when optimizing. This means - // ieeeFlags tests cannot be reliably checked in optimized code. - // See https://github.com/ldc-developers/ldc/issues/888 -} -else -{ - version = IeeeFlagsUnittest; - version = FloatingPointControlUnittest; -} - version (IeeeFlagsSupport) { @@ -368,7 +348,7 @@ public: } /// -version (IeeeFlagsUnittest) +version (StdDdoc) @safe unittest { import std.math.traits : isNaN; @@ -376,17 +356,14 @@ version (IeeeFlagsUnittest) static void func() { int a = 10 * 10; } - pragma(inline, false) static void blockopt(ref real x) {} real a = 3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); - blockopt(a); // avoid constant propagation by the optimizer // Perform a division by zero. a /= 0.0L; assert(a == real.infinity); assert(ieeeFlags.divByZero); - blockopt(a); // avoid constant propagation by the optimizer // Create a NaN a *= 0.0L; assert(ieeeFlags.invalid); @@ -399,7 +376,33 @@ version (IeeeFlagsUnittest) assert(ieeeFlags == f); } -version (IeeeFlagsUnittest) +@safe unittest +{ + import std.math.traits : isNaN; + + static void func() { + int a = 10 * 10; + } + real a = 3.5; + // Set all the flags to zero + resetIeeeFlags(); + assert(!ieeeFlags.divByZero); + // Perform a division by zero. + a = forceDivOp(a, 0.0L); + assert(a == real.infinity); + assert(ieeeFlags.divByZero); + // Create a NaN + a = forceMulOp(a, 0.0L); + assert(ieeeFlags.invalid); + assert(isNaN(a)); + + // Check that calling func() has no effect on the + // status flags. + IeeeFlags f = ieeeFlags; + func(); + assert(ieeeFlags == f); +} + @safe unittest { import std.meta : AliasSeq; @@ -412,27 +415,26 @@ version (IeeeFlagsUnittest) static foreach (T; AliasSeq!(float, double, real)) {{ - T x; /* Needs to be here to trick -O. It would optimize away the - calculations if x were local to the function literals. */ + T x; // Needs to be here to avoid `call without side effects` warning. auto tests = [ Test( - () { x = 1; x += 0.1L; }, + () { x = forceAddOp!T(1, 0.1L); }, () => ieeeFlags.inexact ), Test( - () { x = T.min_normal; x /= T.max; }, + () { x = forceDivOp!T(T.min_normal, T.max); }, () => ieeeFlags.underflow ), Test( - () { x = T.max; x += T.max; }, + () { x = forceAddOp!T(T.max, T.max); }, () => ieeeFlags.overflow ), Test( - () { x = 1; x /= 0; }, + () { x = forceDivOp!T(1, 0); }, () => ieeeFlags.divByZero ), Test( - () { x = 0; x /= 0; }, + () { x = forceDivOp!T(0, 0); }, () => ieeeFlags.invalid ) ]; @@ -453,14 +455,24 @@ void resetIeeeFlags() @trusted nothrow @nogc } /// +version (StdDdoc) @safe unittest { - pragma(inline, false) static void blockopt(ref real x) {} resetIeeeFlags(); real a = 3.5; - blockopt(a); // avoid constant propagation by the optimizer a /= 0.0L; - blockopt(a); // avoid constant propagation by the optimizer + assert(a == real.infinity); + assert(ieeeFlags.divByZero); + + resetIeeeFlags(); + assert(!ieeeFlags.divByZero); +} + +@safe unittest +{ + resetIeeeFlags(); + real a = 3.5; + a = forceDivOp(a, 0.0L); assert(a == real.infinity); assert(ieeeFlags.divByZero); @@ -475,25 +487,39 @@ void resetIeeeFlags() @trusted nothrow @nogc } /// +version (StdDdoc) @safe nothrow unittest { import std.math.traits : isNaN; - pragma(inline, false) static void blockopt(ref real x) {} resetIeeeFlags(); real a = 3.5; - blockopt(a); // avoid constant propagation by the optimizer a /= 0.0L; assert(a == real.infinity); assert(ieeeFlags.divByZero); - blockopt(a); // avoid constant propagation by the optimizer a *= 0.0L; assert(isNaN(a)); assert(ieeeFlags.invalid); } +@safe nothrow unittest +{ + import std.math.traits : isNaN; + + resetIeeeFlags(); + real a = 3.5; + + a = forceDivOp(a, 0.0L); + assert(a == real.infinity); + assert(ieeeFlags.divByZero); + + a = forceMulOp(a, 0.0L); + assert(isNaN(a)); + assert(ieeeFlags.invalid); +} + } // IeeeFlagsSupport @@ -1100,7 +1126,6 @@ private: } /// -version (FloatingPointControlUnittest) @safe unittest { import std.math.rounding : lrint; @@ -1154,32 +1179,27 @@ version (FloatingPointControlUnittest) ensureDefaults(); } -version (FloatingPointControlUnittest) @safe unittest // rounding { import std.meta : AliasSeq; static T addRound(T)(uint rm) { - pragma(inline, false) static void blockopt(ref T x) {} pragma(inline, false); FloatingPointControl fpctrl; fpctrl.rounding = rm; T x = 1; - blockopt(x); // avoid constant propagation by the optimizer - x += 0.1L; + x = forceAddOp(x, 0.1L); return x; } static T subRound(T)(uint rm) { - pragma(inline, false) static void blockopt(ref T x) {} pragma(inline, false); FloatingPointControl fpctrl; fpctrl.rounding = rm; T x = -1; - blockopt(x); // avoid constant propagation by the optimizer - x -= 0.1L; + x = forceSubOp(x, 0.1L); return x; } @@ -1210,4 +1230,16 @@ version (FloatingPointControlUnittest) }} } +} // FloatingPointControlSupport + +version (StdUnittest) +{ + // These helpers are intended to avoid constant propagation by the optimizer. + pragma(inline, false) private @safe + { + T forceAddOp(T)(T x, T y) { return x + y; } + T forceSubOp(T)(T x, T y) { return x - y; } + T forceMulOp(T)(T x, T y) { return x * y; } + T forceDivOp(T)(T x, T y) { return x / y; } + } } diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d index d4fe8a1..3eaa283 100644 --- a/libphobos/src/std/process.d +++ b/libphobos/src/std/process.d @@ -1428,7 +1428,7 @@ version (Posix) @system unittest for (; environ[i] != null; ++i) { assert(e2[i] != null); - import core.stdc.string; + import core.stdc.string : strcmp; assert(strcmp(e2[i], environ[i]) == 0); } assert(e2[i] == null); @@ -1732,7 +1732,9 @@ version (Posix) @system unittest // Pipes void testPipes(Config config) { - import std.file, std.uuid, core.thread, std.exception; + import std.file : tempDir, exists, remove; + import std.uuid : randomUUID; + import std.exception : collectException; auto pipei = pipe(); auto pipeo = pipe(); auto pipee = pipe(); @@ -1753,11 +1755,14 @@ version (Posix) @system unittest // Files void testFiles(Config config) { - import std.ascii, std.file, std.uuid, core.thread, std.exception; + import std.ascii : newline; + import std.file : tempDir, exists, remove, readText, write; + import std.uuid : randomUUID; + import std.exception : collectException; auto pathi = buildPath(tempDir(), randomUUID().toString()); auto patho = buildPath(tempDir(), randomUUID().toString()); auto pathe = buildPath(tempDir(), randomUUID().toString()); - std.file.write(pathi, "INPUT"~std.ascii.newline); + write(pathi, "INPUT" ~ newline); auto filei = File(pathi, "r"); auto fileo = File(patho, "w"); auto filee = File(pathe, "w"); diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d index 9197134..888ac1a 100644 --- a/libphobos/src/std/range/package.d +++ b/libphobos/src/std/range/package.d @@ -3774,10 +3774,17 @@ private: alias fun = Fun[0]; enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; + + import std.traits : hasIndirections; + static if (!hasIndirections!(ReturnType!fun)) + alias RetType = Unqual!(ReturnType!fun); + else + alias RetType = ReturnType!fun; + static if (returnByRef_) - ReturnType!fun *elem_; + RetType *elem_; else - ReturnType!fun elem_; + RetType elem_; public: /// Range primitives enum empty = false; @@ -3866,6 +3873,13 @@ public: assert(g.front == f + 5); } +// https://issues.dlang.org/show_bug.cgi?id=23319 +@safe pure nothrow unittest +{ + auto b = generate!(() => const(int)(42)); + assert(b.front == 42); +} + /** Repeats the given forward range ad infinitum. If the original range is infinite (fact that would make `Cycle` the identity application), @@ -6856,6 +6870,7 @@ if (!isIntegral!(CommonType!(B, E)) && assert(!empty); ++current; } + @property auto save() { return this; } } return Result(begin, end); } @@ -6890,6 +6905,13 @@ if (!isIntegral!(CommonType!(B, E)) && assert(i2.equal([3, 4, 0, 1 ])); } +// https://issues.dlang.org/show_bug.cgi?id=23453 +@safe unittest +{ + auto r = iota('a', 'z'); + static assert(isForwardRange!(typeof(r))); +} + /** Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges (below). diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d index fb2c2d4..593052e 100644 --- a/libphobos/src/std/socket.d +++ b/libphobos/src/std/socket.d @@ -2628,7 +2628,7 @@ private: AddressFamily _family; version (Windows) - bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking. + bool _blocking = true; /// Property to get or set whether the socket is blocking or nonblocking. // The WinSock timeouts seem to be effectively skewed by a constant // offset of about half a second (value in milliseconds). This has @@ -2641,22 +2641,22 @@ private: { if (runSlowTests) softUnittest({ - import std.datetime.stopwatch; - import std.typecons; + import std.datetime.stopwatch : StopWatch; + import std.typecons : Yes; enum msecs = 1000; auto pair = socketPair(); - auto sock = pair[0]; - sock.setOption(SocketOptionLevel.SOCKET, + auto testSock = pair[0]; + testSock.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"msecs"(msecs)); auto sw = StopWatch(Yes.autoStart); ubyte[1] buf; - sock.receive(buf); + testSock.receive(buf); sw.stop(); Duration readBack = void; - sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack); + testSock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack); assert(readBack.total!"msecs" == msecs); assert(sw.peek().total!"msecs" > msecs - 100 && sw.peek().total!"msecs" < msecs + 100); @@ -2751,6 +2751,21 @@ public: } /** + * Releases the underlying socket handle from the Socket object. Once it + * is released, you cannot use the Socket object's methods anymore. This + * also means the Socket destructor will no longer close the socket - it + * becomes your responsibility. + * + * To get the handle without releasing it, use the `handle` property. + */ + @property socket_t release() pure nothrow @nogc + { + auto h = sock; + this.sock = socket_t.init; + return h; + } + + /** * Get/set socket's blocking flag. * * When a socket is blocking, calls to receive(), accept(), and send() diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index ffd6da8..802aa128 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -52,7 +52,7 @@ import std.algorithm.mutation : copy; import std.meta : allSatisfy; import std.range : ElementEncodingType, empty, front, isBidirectionalRange, isInputRange, isSomeFiniteCharInputRange, put; -import std.traits : isSomeChar, isSomeString, Unqual, isPointer; +import std.traits : isSomeChar, isSomeString, Unqual; import std.typecons : Flag, No, Yes; /++ @@ -768,7 +768,7 @@ Throws: `ErrnoException` in case of error. _name = name; } - @system unittest // Test changing filename + @safe unittest // Test changing filename { import std.exception : assertThrown, assertNotThrown; static import std.file; @@ -790,7 +790,7 @@ Throws: `ErrnoException` in case of error. version (CRuntime_DigitalMars) {} else // Not implemented version (CRuntime_Microsoft) {} else // Not implemented - @system unittest // Test changing mode + @safe unittest // Test changing mode { import std.exception : assertThrown, assertNotThrown; static import std.file; @@ -1853,15 +1853,15 @@ void main() } --- */ - S readln(S = string)(dchar terminator = '\n') + S readln(S = string)(dchar terminator = '\n') @safe if (isSomeString!S) { Unqual!(ElementEncodingType!S)[] buf; readln(buf, terminator); - return cast(S) buf; + return (() @trusted => cast(S) buf)(); } - @system unittest + @safe unittest { import std.algorithm.comparison : equal; static import std.file; @@ -1885,7 +1885,7 @@ void main() }} } - @system unittest + @safe unittest { static import std.file; import std.typecons : Tuple; @@ -1984,7 +1984,7 @@ void main() This is actually what $(LREF byLine) does internally, so its usage is recommended if you want to process a complete file. */ - size_t readln(C)(ref C[] buf, dchar terminator = '\n') + size_t readln(C)(ref C[] buf, dchar terminator = '\n') @safe if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) { import std.exception : enforce; @@ -2020,9 +2020,8 @@ is recommended if you want to process a complete file. } } - @system unittest + @safe unittest { - // @system due to readln static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "123\n456789"); @@ -2039,7 +2038,7 @@ is recommended if you want to process a complete file. } // https://issues.dlang.org/show_bug.cgi?id=15293 - @system unittest + @safe unittest { // @system due to readln static import std.file; @@ -2063,7 +2062,7 @@ is recommended if you want to process a complete file. } /** ditto */ - size_t readln(C, R)(ref C[] buf, R terminator) + size_t readln(C, R)(ref C[] buf, R terminator) @safe if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) && isBidirectionalRange!R && is(typeof(terminator.front == dchar.init))) { @@ -2093,7 +2092,7 @@ is recommended if you want to process a complete file. return buf.length; } - @system unittest + @safe unittest { static import std.file; import std.typecons : Tuple; @@ -3735,9 +3734,8 @@ void main() assert(f.tell == 0); } -@system unittest +@safe unittest { - // @system due to readln static import std.file; import std.range : chain, only, repeat; import std.range.primitives : isOutputRange; @@ -5169,13 +5167,13 @@ Initialize with a message and an error code. } /** Convenience functions that throw an `StdioException`. */ - static void opCall(string msg) + static void opCall(string msg) @safe { throw new StdioException(msg); } /// ditto - static void opCall() + static void opCall() @safe { throw new StdioException(null, core.stdc.errno.errno); } @@ -5388,7 +5386,7 @@ private struct ReadlnAppender size_t pos; bool safeAppend = false; - void initialize(char[] b) + void initialize(char[] b) @safe { buf = b; pos = 0; @@ -5445,7 +5443,7 @@ private struct ReadlnAppender foreach (c; ubuf) buf.ptr[pos++] = c; } - void putonly(char[] b) @trusted + void putonly(const char[] b) @trusted { import core.stdc.string : memcpy; assert(pos == 0); // assume this is the only put call @@ -5457,28 +5455,60 @@ private struct ReadlnAppender } } -// Private implementation of readln -private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) +private struct LockedFile { - version (DIGITAL_MARS_STDIO) + private @system _iobuf* fp; + + this(FILE* fps) @trusted { _FLOCK(fps); - scope(exit) _FUNLOCK(fps); + // Since fps is now locked, we can cast away shared + fp = cast(_iobuf*) fps; + } + + @disable this(); + @disable this(this); + @disable void opAssign(LockedFile); - /* Since fps is now locked, we can create an "unshared" version - * of fp. - */ - auto fp = cast(_iobuf*) fps; + // these use unlocked fgetc calls + @trusted fgetc() { return _FGETC(fp); } + @trusted fgetwc() { return _FGETWC(fp); } + ~this() @trusted + { + _FUNLOCK(cast(FILE*) fp); + } +} + +@safe unittest +{ + void f() @safe + { + FILE* fps; + auto lf = LockedFile(fps); + static assert(!__traits(compiles, lf = LockedFile(fps))); + version (ShouldFail) + { + lf.fps = null; // error with -preview=systemVariables + } + } +} + +// Private implementation of readln +private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) @safe +{ + version (DIGITAL_MARS_STDIO) + return () @trusted { + auto lf = LockedFile(fps); ReadlnAppender app; app.initialize(buf); - if (__fhnd_info[fp._file] & FHND_WCHAR) + if (__fhnd_info[lf.fp._file] & FHND_WCHAR) { /* Stream is in wide characters. * Read them and convert to chars. */ static assert(wchar_t.sizeof == 2); - for (int c = void; (c = _FGETWC(fp)) != -1; ) + for (int c = void; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { @@ -5491,7 +5521,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5504,8 +5534,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (ferror(fps)) StdioException(); } - - else if (fp._flag & _IONBF) + else if (lf.fp._flag & _IONBF) { /* Use this for unbuffered I/O, when running * across buffer boundaries, or for any but the common @@ -5513,7 +5542,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie */ L1: int c; - while ((c = _FGETC(fp)) != -1) + while ((c = lf.fgetc()) != -1) { app.putchar(cast(char) c); if (c == terminator) @@ -5529,10 +5558,10 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } else { - int u = fp._cnt; - char* p = fp._ptr; + int u = lf.fp._cnt; + char* p = lf.fp._ptr; int i; - if (fp._flag & _IOTRAN) + if (lf.fp._flag & _IOTRAN) { /* Translated mode ignores \r and treats ^Z as end-of-file */ char c; @@ -5574,28 +5603,22 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } app.putonly(p[0 .. i]); } - fp._cnt -= i; - fp._ptr += i; + lf.fp._cnt -= i; + lf.fp._ptr += i; } buf = app.data; return buf.length; - } + }(); else version (MICROSOFT_STDIO) { - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - - /* Since fps is now locked, we can create an "unshared" version - * of fp. - */ - auto fp = cast(_iobuf*) fps; + auto lf = LockedFile(fps); ReadlnAppender app; app.initialize(buf); int c; - while ((c = _FGETC(fp)) != -1) + while ((c = lf.fgetc()) != -1) { app.putchar(cast(char) c); if (c == terminator) @@ -5613,21 +5636,18 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } else static if (__traits(compiles, core.sys.posix.stdio.getdelim)) { - import core.stdc.stdlib : free; - import core.stdc.wchar_ : fwide; - if (orientation == File.Orientation.wide) { + import core.stdc.wchar_ : fwide; + + auto lf = LockedFile(fps); /* Stream is in wide characters. * Read them and convert to chars. */ - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - auto fp = cast(_iobuf*) fps; version (Windows) { buf.length = 0; - for (int c = void; (c = _FGETWC(fp)) != -1; ) + for (int c = void; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; @@ -5639,7 +5659,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5650,14 +5670,14 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie encode(buf, c); } } - if (ferror(fp)) + if (ferror(fps)) StdioException(); return buf.length; } else version (Posix) { buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { import std.utf : encode; @@ -5677,47 +5697,49 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie static assert(0); } } + return () @trusted { + import core.stdc.stdlib : free; - static char *lineptr = null; - static size_t n = 0; - scope(exit) - { - if (n > 128 * 1024) + static char *lineptr = null; + static size_t n = 0; + scope(exit) { - // Bound memory used by readln - free(lineptr); - lineptr = null; - n = 0; + if (n > 128 * 1024) + { + // Bound memory used by readln + free(lineptr); + lineptr = null; + n = 0; + } } - } - auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps); - if (s < 0) - { - if (ferror(fps)) - StdioException(); - buf.length = 0; // end of file - return 0; - } + const s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps); + if (s < 0) + { + if (ferror(fps)) + StdioException(); + buf.length = 0; // end of file + return 0; + } - if (s <= buf.length) - { - buf = buf[0 .. s]; - buf[] = lineptr[0 .. s]; - } - else - { - buf = lineptr[0 .. s].dup; - } - return s; + const line = lineptr[0 .. s]; + if (s <= buf.length) + { + buf = buf[0 .. s]; + buf[] = line; + } + else + { + buf = line.dup; + } + return s; + }(); } else // version (NO_GETDELIM) { import core.stdc.wchar_ : fwide; - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - auto fp = cast(_iobuf*) fps; + auto lf = LockedFile(fps); if (orientation == File.Orientation.wide) { /* Stream is in wide characters. @@ -5726,7 +5748,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie version (Windows) { buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; @@ -5738,7 +5760,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5749,7 +5771,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie encode(buf, c); } } - if (ferror(fp)) + if (ferror(fps)) StdioException(); return buf.length; } @@ -5757,7 +5779,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie { import std.utf : encode; buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) buf ~= cast(char) c; @@ -5780,7 +5802,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie // First, fill the existing buffer for (size_t bufPos = 0; bufPos < buf.length; ) { - immutable c = _FGETC(fp); + immutable c = lf.fgetc(); if (c == -1) { buf.length = bufPos; @@ -5795,7 +5817,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } } // Then, append to it - for (int c; (c = _FGETC(fp)) != -1; ) + for (int c; (c = lf.fgetc()) != -1; ) { buf ~= cast(char) c; if (c == terminator) diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index ee2d73a..4e76156 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -1952,10 +1952,10 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) // An array that maps caseIds to handler indices ("hids"). enum matches = () { - size_t[numCases] matches; + size_t[numCases] result; // Workaround for https://issues.dlang.org/show_bug.cgi?id=19561 - foreach (ref match; matches) + foreach (ref match; result) { match = noMatch; } @@ -1966,15 +1966,15 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) { static if (canMatch!(handler, valueTypes!caseId)) { - if (matches[caseId] == noMatch) + if (result[caseId] == noMatch) { - matches[caseId] = hid; + result[caseId] = hid; } } } } - return matches; + return result; }(); import std.algorithm.searching : canFind; diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d index 1cbff84..e5f305b 100644 --- a/libphobos/src/std/traits.d +++ b/libphobos/src/std/traits.d @@ -889,10 +889,10 @@ private template fqnType(T, ); } } - else static if (isPointer!T) + else static if (is(T : U*, U)) { enum fqnType = chain!( - fqnType!(PointerTarget!T, qualifiers) ~ "*" + fqnType!(U, qualifiers) ~ "*" ); } else static if (is(T : __vector(V[N]), V, size_t N)) @@ -3925,8 +3925,8 @@ template hasStaticMember(T, string member) { static if (__traits(hasMember, T, member)) { - static if (isPointer!T) - alias U = PointerTarget!T; + static if (is(T : V*, V)) + alias U = V; else alias U = T; @@ -5446,8 +5446,8 @@ private template isStorageClassImplicitlyConvertible(From, To) { alias Pointify(T) = void*; - enum isStorageClassImplicitlyConvertible = isImplicitlyConvertible!( - ModifyTypePreservingTQ!(Pointify, From), + enum isStorageClassImplicitlyConvertible = is( + ModifyTypePreservingTQ!(Pointify, From) : ModifyTypePreservingTQ!(Pointify, To) ); } @@ -7138,7 +7138,7 @@ enum bool isSIMDVector(T) = is(T : __vector(V[N]), V, size_t N); /** * Detect whether type `T` is a pointer. */ -enum bool isPointer(T) = is(T == U*, U) && __traits(isScalar, T); +enum bool isPointer(T) = is(T == U*, U); /// @safe unittest @@ -8847,6 +8847,14 @@ version (StdUnittest) static assert(__traits(compiles, getSymbolsByUDA!(mixin(__MODULE__), "Issue20054"))); } +private template isAliasSeq(Args...) +{ + static if (Args.length != 1) + enum isAliasSeq = true; + else + enum isAliasSeq = false; +} + private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...) { import std.meta : Alias, AliasSeq, Filter; @@ -8868,12 +8876,12 @@ private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...) alias member = __traits(getMember, symbol, names[0]); // Filtering not compiled members such as alias of basic types. - static if (!__traits(compiles, hasUDA!(member, attribute))) + static if (isAliasSeq!member || isType!member) { alias getSymbolsByUDAImpl = tail; } - // Get overloads for functions, in case different overloads have different sets of UDAs. - else static if (isFunction!member) + // If a symbol is overloaded, get UDAs for each overload (including templated overlaods). + else static if (__traits(getOverloads, symbol, names[0], true).length > 0) { enum hasSpecificUDA(alias member) = hasUDA!(member, attribute); alias overloadsWithUDA = Filter!(hasSpecificUDA, __traits(getOverloads, symbol, names[0])); diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 231ac93..e83b6171 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -5536,7 +5536,7 @@ private static: } // handle each overload set - private string generateCodeForOverloadSet(alias oset)() @property + string generateCodeForOverloadSet(alias oset)() @property { string code = ""; @@ -5666,7 +5666,7 @@ private static: * "ref int a0, real a1, ..." */ static struct GenParams { string imports, params; } - private GenParams generateParameters(string myFuncInfo, func...)() + GenParams generateParameters(string myFuncInfo, func...)() { alias STC = ParameterStorageClass; alias stcs = ParameterStorageClassTuple!(func); @@ -5716,7 +5716,7 @@ private static: // Returns D code which enumerates n parameter variables using comma as the // separator. "a0, a1, a2, a3" - private string enumerateParameters(size_t n)() @property + string enumerateParameters(size_t n)() @property { string params = ""; @@ -8782,7 +8782,7 @@ if (alignment > 0 && !((alignment - 1) & alignment)) { void test(size_t size) { - import core.stdc.stdlib; + import core.stdc.stdlib : alloca; cast(void) alloca(size); alignmentTest(); } @@ -9253,7 +9253,7 @@ public: } Base opCast(B)() const - if (isImplicitlyConvertible!(Base, B)) + if (is(Base : B)) { return mValue; } diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 81b949e..c31912a 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -6271,8 +6271,8 @@ struct UnicodeSetParser(Range) { if (casefold_) { - auto range = simpleCaseFoldings(ch); - foreach (v; range) + auto foldings = simpleCaseFoldings(ch); + foreach (v; foldings) set |= v; } else diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index 8d94e12..7a0556d 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -66,7 +66,7 @@ import std.exception : basicExceptionCtors; import core.exception : UnicodeException; import std.meta : AliasSeq; import std.range; -import std.traits : isAutodecodableString, isConvertibleToString, isPointer, +import std.traits : isAutodecodableString, isConvertibleToString, isSomeChar, isSomeString, isStaticArray, Unqual; import std.typecons : Flag, Yes, No; @@ -3136,7 +3136,7 @@ private T toUTFImpl(T, S)(scope S s) collection cycle and cause a nasty bug when the C code tries to use it. +/ template toUTFz(P) -if (isPointer!P && isSomeChar!(typeof(*P.init))) +if (is(P : C*, C) && isSomeChar!C) { P toUTFz(S)(S str) @safe pure if (isSomeString!S) diff --git a/libphobos/src/std/windows/registry.d b/libphobos/src/std/windows/registry.d index d66adff..7ee1f7a 100644 --- a/libphobos/src/std/windows/registry.d +++ b/libphobos/src/std/windows/registry.d @@ -1856,7 +1856,7 @@ private: if (i++ > 0) break; - import core.memory; + import core.memory : GC; GC.collect(); } assert(i == 2); |