From 052941a08788593f1477188aa36cbc3b48cbbb83 Mon Sep 17 00:00:00 2001 From: dsimcha Date: Sun, 11 Dec 2011 12:38:45 -0500 Subject: [PATCH 01/33] Add opDollar aliases for std.range and std.algorithm. --- std/algorithm.d | 7 +++++++ std/range.d | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/std/algorithm.d b/std/algorithm.d index 3fedb37e0ff..bfd54cdecb2 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -437,6 +437,8 @@ template map(fun...) if (fun.length >= 1) { return _input.length; } + + alias length opDollar; } static if (hasSlicing!R) @@ -483,6 +485,7 @@ unittest const int[] arr1Const = arr1; int[] arr2 = [ 5, 6 ]; auto squares = map!("a * a")(arr1Const); + assert(squares[$ - 1] == 16); assert(equal(squares, [ 1, 4, 9, 16 ][])); assert(equal(map!("a * a")(chain(arr1, arr2)), [ 1, 4, 9, 16, 25, 36 ][])); @@ -3264,6 +3267,8 @@ public: { return needle.length; } + + alias length opDollar; } /// Ditto @@ -7928,6 +7933,8 @@ public: } return result; } + + alias length opDollar; } } diff --git a/std/range.d b/std/range.d index 017c8c881d2..cf37285f12f 100644 --- a/std/range.d +++ b/std/range.d @@ -142,6 +142,8 @@ enum dummyRanges = q{ @property size_t length() { return arr.length; } + + alias length opDollar; } } @@ -600,6 +602,7 @@ unittest void popBack(); ref int opIndex(uint); @property size_t length(); + alias length opDollar; //int opSlice(uint, uint); } static assert(isRandomAccessRange!(D)); @@ -626,6 +629,7 @@ unittest int opIndex(size_t n) const { return 0; } @property size_t length() const { return 0; } + alias length opDollar; void put(int e){ } } @@ -1066,6 +1070,8 @@ if (isBidirectionalRange!(Unqual!Range)) { return source.length; } + + alias length opDollar; } } @@ -1360,10 +1366,14 @@ if (isInputRange!(Unqual!Range)) } static if (hasLength!R) + { @property auto length() { return (source.length + _n - 1) / _n; } + + alias length opDollar; + } } return Result(r, n); } @@ -1706,6 +1716,7 @@ if (Ranges.length > 0 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))) } static if (allSatisfy!(hasLength, R)) + { @property size_t length() { size_t result; @@ -1715,6 +1726,9 @@ if (Ranges.length > 0 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))) } return result; } + + alias length opDollar; + } static if (allSatisfy!(isRandomAccessRange, R)) { @@ -2024,6 +2038,8 @@ if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs))) } return result; } + + alias length opDollar; } } @@ -2185,6 +2201,8 @@ if (isInputRange!(Unqual!Range) { return _maxAvailable; } + + alias length opDollar; } else static if (hasLength!R) { @@ -2192,6 +2210,8 @@ if (isInputRange!(Unqual!Range) { return min(_maxAvailable, source.length); } + + alias length opDollar; } static if (isRandomAccessRange!R) @@ -2412,6 +2432,7 @@ if (isInputRange!R && !hasSlicing!R) } void popFront() { _input.popFront(); --_n; } @property size_t length() const { return _n; } + alias length opDollar; static if (isForwardRange!R) auto save() { return this; } @@ -2505,6 +2526,7 @@ auto takeOne(R)(R source) if (isInputRange!R) auto save() { return Result(_source.save, empty); } @property auto ref back() { assert(!empty); return _source.front; } @property size_t length() const { return !empty; } + alias length opDollar; auto ref opIndex(size_t n) { assert(n < length); return _source.front; } auto opSlice(size_t m, size_t n) { @@ -3257,6 +3279,7 @@ if(Ranges.length && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))) $(D length). */ static if (allSatisfy!(hasLength, R)) + { @property auto length() { CommonType!(staticMap!(lengthType, R)) result = ranges[0].length; @@ -3276,6 +3299,9 @@ if(Ranges.length && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))) } return result; } + + alias length opDollar; + } /** Returns a slice of the range. Defined only if all range define @@ -4056,6 +4082,8 @@ if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) { return unsigned((pastLast - current) / step); } + + alias length opDollar; } return Result(begin, end, step); @@ -4120,6 +4148,8 @@ if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) { return unsigned(pastLast - current); } + + alias length opDollar; } return Result(begin, end); @@ -4203,6 +4233,8 @@ if (isFloatingPoint!(CommonType!(B, E, S))) { return count - index; } + + alias length opDollar; } return Result(begin, end, step); @@ -4212,6 +4244,7 @@ unittest { static assert(hasLength!(typeof(iota(0, 2)))); auto r = iota(0, 10, 1); + assert(r[$ - 1] == 9); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); auto rSlice = r[2..8]; @@ -4806,6 +4839,8 @@ struct Transversal(Ror, { return _input.length; } + + alias length opDollar; } /** @@ -5096,6 +5131,8 @@ if(isRandomAccessRange!Source && isInputRange!Indices && { return _indices.length; } + + alias length opDollar; } static if(isRandomAccessRange!Indices) @@ -5290,6 +5327,8 @@ struct Chunks(Source) if(hasSlicing!Source && hasLength!Source) return (_source.length / _chunkSize) + (_source.length % _chunkSize > 0); } + + alias length opDollar; /// Ditto @property auto back() @@ -5582,6 +5621,9 @@ interface RandomAccessFinite(E) : BidirectionalRange!(E) { /// @property size_t length(); + + /// + alias length opDollar; // Can't support slicing until issues with requiring slicing for all // finite random access ranges are fully resolved. @@ -5781,6 +5823,8 @@ template InputRangeObject(R) if (isInputRange!(Unqual!R)) { @property size_t length() { return _range.length; } + + alias length opDollar; // Can't support slicing until all the issues with // requiring slicing support for finite random access @@ -6086,6 +6130,8 @@ if (isRandomAccessRange!Range) { return _input.length; } + + alias length opDollar; /** Releases the controlled range and returns it. From d3e1992d86aed14ea762e74ecb09b532c630dde8 Mon Sep 17 00:00:00 2001 From: k-hara Date: Mon, 3 Oct 2011 09:01:03 +0900 Subject: [PATCH 02/33] Add overloads for struct literal and construction that now make rvalue. --- std/bigint.d | 2 +- std/concurrency.d | 9 ++++++--- std/container.d | 12 ++++++++++++ std/datetime.d | 12 ++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/std/bigint.d b/std/bigint.d index 71849cfa3f4..6a24de3f363 100644 --- a/std/bigint.d +++ b/std/bigint.d @@ -336,7 +336,7 @@ public: } /// - bool opEquals(Tdummy=void)(ref const BigInt y) const + bool opEquals()(auto ref const BigInt y) const { return sign == y.sign && y.data == data; } diff --git a/std/concurrency.d b/std/concurrency.d index 00f33afdf44..fb251825eb6 100644 --- a/std/concurrency.d +++ b/std/concurrency.d @@ -496,7 +496,8 @@ private void _send(T...)( Tid tid, T vals ) */ private void _send(T...)( MsgType type, Tid tid, T vals ) { - tid.mbox.put( Message( type, vals ) ); + auto msg = Message( type, vals ); + tid.mbox.put( msg ); } @@ -1042,7 +1043,8 @@ private if( *depends && tid != owner ) { auto e = new LinkTerminated( tid ); - if( onStandardMsg( Message( MsgType.standard, e ) ) ) + auto msg = Message( MsgType.standard, e ); + if( onStandardMsg( msg ) ) return true; throw e; } @@ -1051,7 +1053,8 @@ private { owner = Tid.init; auto e = new OwnerTerminated( tid ); - if( onStandardMsg( Message( MsgType.standard, e ) ) ) + auto msg = Message( MsgType.standard, e ); + if( onStandardMsg( msg ) ) return true; throw e; } diff --git a/std/container.d b/std/container.d index 002cf770be5..c39192eb57c 100644 --- a/std/container.d +++ b/std/container.d @@ -922,6 +922,12 @@ Comparison for equality. Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of elements in $(D rhs). */ + bool opEquals(const SList rhs) const + { + return opEquals(rhs); + } + + /// ditto bool opEquals(ref const SList rhs) const { const(Node) * n1 = _root, n2 = rhs._root; @@ -1634,6 +1640,12 @@ struct Array(T) if (!is(T : const(bool))) /** Comparison for equality. */ + bool opEquals(const Array rhs) const + { + return opEquals(rhs); + } + + /// ditto bool opEquals(ref const Array rhs) const { if (empty) return rhs.empty; diff --git a/std/datetime.d b/std/datetime.d index 0c83d1db3bf..6c27f154bea 100644 --- a/std/datetime.d +++ b/std/datetime.d @@ -799,6 +799,12 @@ public: Note that the time zone is ignored. Only the internal std times (which are in UTC) are compared. +/ + bool opEquals(const SysTime rhs) const pure nothrow + { + return opEquals(rhs); + } + + /// ditto bool opEquals(const ref SysTime rhs) const pure nothrow { return _stdTime == rhs._stdTime; @@ -30816,6 +30822,12 @@ public: /// + bool opEquals(const StopWatch rhs) const pure nothrow + { + return opEquals(rhs); + } + + /// ditto bool opEquals(const ref StopWatch rhs) const pure nothrow { return _timeStart == rhs._timeStart && From bb05d579a2f45084972d9116467f7d1b84f2103f Mon Sep 17 00:00:00 2001 From: KennyTM~ Date: Mon, 6 Feb 2012 04:51:09 +0800 Subject: [PATCH 03/33] Add 'pure' attribute to toUTF8, toUTF16 & toUTF32. --- std/utf.d | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/std/utf.d b/std/utf.d index 1982a4f15ae..434db0b4422 100644 --- a/std/utf.d +++ b/std/utf.d @@ -74,13 +74,14 @@ class UTFException : Exception override string toString() { + import std.string; if(len == 0) return super.toString(); string result = "Invalid UTF sequence:"; foreach(i; sequence[0 .. len]) - result ~= " " ~ to!string(i, 16); + result ~= format(" %02x", i); if(super.msg.length > 0) { @@ -1183,10 +1184,10 @@ void validate(S)(in S str) @safe pure /* =================== Conversion to UTF8 ======================= */ -@trusted +pure { -char[] toUTF8(out char[4] buf, dchar c) +char[] toUTF8(out char[4] buf, dchar c) nothrow @safe in { assert(isValidDchar(c)); @@ -1227,14 +1228,14 @@ body /******************* * Encodes string $(D_PARAM s) into UTF-8 and returns the encoded string. */ -string toUTF8(in char[] s) +string toUTF8(in char[] s) @safe { validate(s); return s.idup; } /// ditto -string toUTF8(in wchar[] s) +string toUTF8(in wchar[] s) @trusted { char[] r; size_t i; @@ -1260,7 +1261,7 @@ string toUTF8(in wchar[] s) } /// ditto -pure string toUTF8(in dchar[] s) +string toUTF8(in dchar[] s) @trusted { char[] r; size_t i; @@ -1290,7 +1291,7 @@ pure string toUTF8(in dchar[] s) /* =================== Conversion to UTF16 ======================= */ -pure wchar[] toUTF16(ref wchar[2] buf, dchar c) +wchar[] toUTF16(ref wchar[2] buf, dchar c) nothrow @safe in { assert(isValidDchar(c)); @@ -1313,7 +1314,7 @@ body /**************** * Encodes string $(D s) into UTF-16 and returns the encoded string. */ -wstring toUTF16(in char[] s) +wstring toUTF16(in char[] s) @trusted { wchar[] r; size_t slen = s.length; @@ -1339,14 +1340,14 @@ wstring toUTF16(in char[] s) } /// ditto -wstring toUTF16(in wchar[] s) +wstring toUTF16(in wchar[] s) @safe { validate(s); return s.idup; } /// ditto -pure wstring toUTF16(in dchar[] s) +pure wstring toUTF16(in dchar[] s) @trusted { wchar[] r; size_t slen = s.length; @@ -1366,7 +1367,7 @@ pure wstring toUTF16(in dchar[] s) $(D toUTF16z) is suitable for calling the 'W' functions in the Win32 API that take an $(D LPWSTR) or $(D LPCWSTR) argument. +/ -const(wchar)* toUTF16z(in char[] s) +const(wchar)* toUTF16z(in char[] s) @trusted { wchar[] r; size_t slen = s.length; @@ -1398,7 +1399,7 @@ const(wchar)* toUTF16z(in char[] s) /***** * Encodes string $(D_PARAM s) into UTF-32 and returns the encoded string. */ -dstring toUTF32(in char[] s) +dstring toUTF32(in char[] s) @trusted { dchar[] r; size_t slen = s.length; @@ -1419,7 +1420,7 @@ dstring toUTF32(in char[] s) } /// ditto -dstring toUTF32(in wchar[] s) +dstring toUTF32(in wchar[] s) @trusted { dchar[] r; size_t slen = s.length; @@ -1440,7 +1441,7 @@ dstring toUTF32(in wchar[] s) } /// ditto -dstring toUTF32(in dchar[] s) +dstring toUTF32(in dchar[] s) @safe { validate(s); return s.idup; @@ -1767,3 +1768,4 @@ unittest assert(count("abc") == 3); assert(count("\u20AC100") == 4); } + From 539ff6a68b05636955a10c999cb3e9bf1bb8523a Mon Sep 17 00:00:00 2001 From: qchikara Date: Thu, 9 Feb 2012 15:17:01 +0900 Subject: [PATCH 04/33] Issue 7460 - std.windows.registry reports a false exception message --- std/windows/registry.d | 43 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/std/windows/registry.d b/std/windows/registry.d index c6875357e1d..cab863f7354 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -89,16 +89,39 @@ class Win32Exception : Exception this(string message, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { - super(msg, fn, ln, next); + super(message, fn, ln, next); } - this(string msg, int errnum, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) + this(string message, int errnum, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { - super(text(msg, " (", error, ")"), fn, ln, next); + super(text(message, " (", errnum, ")"), fn, ln, next); error = errnum; } } +unittest { + // Test that we can throw and catch one by its own type + string message = "Test W1"; + + auto e = collectException!Win32Exception( + enforce(false, new Win32Exception(message))); + assert(e.msg == message); +} + +unittest { + // ditto + string message = "Test W2"; + int code = 5; + + auto e = collectException!Win32Exception( + enforce(false, new Win32Exception(message, code))); + assert(e.error == code); + + // CAUTION: this test is to be removed in D1 + // because e.msg does not contains the (code) section. + assert(e.msg == text(message, " (", code, ")")); +} + /** Exception class thrown by the std.windows.registry classes. */ @@ -139,6 +162,20 @@ unittest auto e = collectException!RegistryException( enforce(false, new RegistryException(message, code))); assert(e.error == code); + + // CAUTION: this test is to be removed in D1 + // because e.msg does not contains the (code) section. + assert(e.msg == text(message, " (", code, ")")); +} + +unittest +{ + // ditto + string message = "Test 2"; + + auto e = collectException!RegistryException( + enforce(false, new RegistryException(message))); + assert(e.msg == message); } /* ************* public enumerations *************** */ From 6a768c3c4171026469ad8b2ef251d84774344da0 Mon Sep 17 00:00:00 2001 From: qchikara Date: Thu, 9 Feb 2012 15:19:31 +0900 Subject: [PATCH 05/33] error message fix:"Value" to "Key" --- std/windows/registry.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/windows/registry.d b/std/windows/registry.d index cab863f7354..428d82e1b63 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -400,7 +400,7 @@ body useWfuncs ? RegDeleteKeyW(hkey, toUTF16z(subKey)) : RegDeleteKeyA(hkey, toMBSz(subKey)); } - enforceSucc(res, "Value cannot be deleted: \"" ~ subKey ~ "\""); + enforceSucc(res, "Key cannot be deleted: \"" ~ subKey ~ "\""); } private void regDeleteValue(in HKEY hkey, in string valueName) From 99ab2b61757683f28b4e7a6ea8f8c483dff5a3bb Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Tue, 24 Jan 2012 20:22:24 +0400 Subject: [PATCH 06/33] Remove __file.d and it's using * remove `useWfuncs` using * remove std.__file using * remove __file.d * remove variables which have become unnecessary * remove std.windows.charset import and alias in file.d --- posix.mak | 2 +- std/__fileinit.d | 40 ----- std/file.d | 337 +++++++++-------------------------------- std/mmfile.d | 30 +--- std/stream.d | 17 +-- std/windows/registry.d | 305 ++++++++++++------------------------- win32.mak | 6 +- 7 files changed, 191 insertions(+), 546 deletions(-) delete mode 100644 std/__fileinit.d diff --git a/posix.mak b/posix.mak index 207b2fd2ea7..a62a29a92f4 100644 --- a/posix.mak +++ b/posix.mak @@ -194,7 +194,7 @@ D_FILES = $(addsuffix .d,$(D_MODULES)) # Aggregate all D modules over all OSs (this is for the zip file) ALL_D_FILES = $(addsuffix .d, $(D_MODULES) \ $(EXTRA_MODULES_LINUX) $(EXTRA_MODULES_OSX) $(EXTRA_MODULES_FREEBSD) $(EXTRA_MODULES_WIN32)) \ - std/stdarg.d std/bind.d std/internal/windows/advapi32.d std/__fileinit.d \ + std/stdarg.d std/bind.d std/internal/windows/advapi32.d \ std/windows/registry.d std/c/linux/pthread.d std/c/linux/termios.d \ std/c/linux/tipc.d std/net/isemail.d std/net/curl.d diff --git a/std/__fileinit.d b/std/__fileinit.d deleted file mode 100644 index 6a99f6dfc4e..00000000000 --- a/std/__fileinit.d +++ /dev/null @@ -1,40 +0,0 @@ -// Written in the D programming language. - -/** - * The only purpose of this module is to do the static construction for - * std.file, to eliminate cyclic construction errors. - * - * Copyright: Copyright Digital Mars 2008 - 2009. - * License: Boost License 1.0. - * Authors: $(WEB digitalmars.com, Walter Bright) - * Source: $(PHOBOSSRC std/___fileinit.d) - */ - -/* Copyright Digital Mars 2008 - 2009. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - */ -module std.__fileinit; - -version (Windows) -{ - version (Win32) - { - private import std.c.windows.windows; - - //This really should be immutable, but std.windows.registry messes with - //it in its unit tests. - shared bool useWfuncs = true; - - shared static this() - { - // Win 95, 98, ME do not implement the W functions - useWfuncs = (GetVersion() < 0x80000000); - } - } - else version (Win64) - { - enum useWfuncs = true; - } -} diff --git a/std/file.d b/std/file.d index 9ad472be33f..be8881982b4 100644 --- a/std/file.d +++ b/std/file.d @@ -30,16 +30,7 @@ import std.metastrings; //For generating deprecation messages only. Remove once version (Windows) { - import core.sys.windows.windows, std.windows.charset, - std.windows.syserror; - public import std.__fileinit : useWfuncs; -/* - * Since Win 9x does not support the "W" API's, first convert - * to wchar, then convert to multibyte using the current code - * page. - * (Thanks to yaneurao for this) - */ - alias std.windows.charset.toMBSz toMBSz; + import core.sys.windows.windows, std.windows.syserror; } else version (Posix) { @@ -309,9 +300,7 @@ void[] read(in char[] name, size_t upTo = size_t.max) FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init) defaults; - auto h = useWfuncs - ? CreateFileW(std.utf.toUTF16z(name), defaults) - : CreateFileA(toMBSz(name), defaults); + auto h = CreateFileW(std.utf.toUTF16z(name), defaults); cenforce(h != INVALID_HANDLE_VALUE, name); scope(exit) cenforce(CloseHandle(h), name); @@ -446,9 +435,7 @@ void write(in char[] name, const void[] buffer) FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init) defaults; - auto h = useWfuncs - ? CreateFileW(std.utf.toUTF16z(name), defaults) - : CreateFileA(toMBSz(name), defaults); + auto h = CreateFileW(std.utf.toUTF16z(name), defaults); cenforce(h != INVALID_HANDLE_VALUE, name); scope(exit) cenforce(CloseHandle(h), name); @@ -487,9 +474,7 @@ void append(in char[] name, in void[] buffer) FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,HANDLE.init) defaults; - auto h = useWfuncs - ? CreateFileW(std.utf.toUTF16z(name), defaults) - : CreateFileA(toMBSz(name), defaults); + auto h = CreateFileW(std.utf.toUTF16z(name), defaults); cenforce(h != INVALID_HANDLE_VALUE, name); scope(exit) cenforce(CloseHandle(h), name); @@ -529,9 +514,7 @@ void rename(in char[] from, in char[] to) { version(Windows) { - enforce(useWfuncs - ? MoveFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to)) - : MoveFileA(toMBSz(from), toMBSz(to)), + enforce(MoveFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to)), new FileException( text("Attempting to rename file ", from, " to ", to))); @@ -548,10 +531,7 @@ void remove(in char[] name) { version(Windows) { - cenforce(useWfuncs - ? DeleteFileW(std.utf.toUTF16z(name)) - : DeleteFileA(toMBSz(name)), - name); + cenforce(DeleteFileW(std.utf.toUTF16z(name)), name); } else version(Posix) cenforce(core.stdc.stdio.remove(toStringz(name)) == 0, @@ -567,31 +547,17 @@ ulong getSize(in char[] name) { version(Windows) { - HANDLE findhndl = void; - uint resulth = void; - uint resultl = void; const (char)[] file = name[]; //FindFirstFileX can't handle file names which end in a backslash. if(file.endsWith(sep)) file.popBackN(sep.length); - if (useWfuncs) - { - WIN32_FIND_DATAW filefindbuf; - - findhndl = FindFirstFileW(std.utf.toUTF16z(file), &filefindbuf); - resulth = filefindbuf.nFileSizeHigh; - resultl = filefindbuf.nFileSizeLow; - } - else - { - WIN32_FIND_DATA filefindbuf; + WIN32_FIND_DATAW filefindbuf; - findhndl = FindFirstFileA(toMBSz(file), &filefindbuf); - resulth = filefindbuf.nFileSizeHigh; - resultl = filefindbuf.nFileSizeLow; - } + HANDLE findhndl = FindFirstFileW(std.utf.toUTF16z(file), &filefindbuf); + uint resulth = filefindbuf.nFileSizeHigh; + uint resultl = filefindbuf.nFileSizeLow; cenforce(findhndl != cast(HANDLE)-1 && FindClose(findhndl), file); return (cast(ulong) resulth << 32) + resultl; @@ -634,26 +600,12 @@ else version(Windows) deprecated void getTimes(C)(in C[] name, "February 2012. Please use either the version of getTimes with " ~ "two arguments or getTimesWin (Windows-Only) instead."); - HANDLE findhndl = void; + WIN32_FIND_DATAW filefindbuf; - if (useWfuncs) - { - WIN32_FIND_DATAW filefindbuf; - - findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); - ftc = FILETIME2d_time(&filefindbuf.ftCreationTime); - fta = FILETIME2d_time(&filefindbuf.ftLastAccessTime); - ftm = FILETIME2d_time(&filefindbuf.ftLastWriteTime); - } - else - { - WIN32_FIND_DATA filefindbuf; - - findhndl = FindFirstFileA(toMBSz(name), &filefindbuf); - ftc = FILETIME2d_time(&filefindbuf.ftCreationTime); - fta = FILETIME2d_time(&filefindbuf.ftLastAccessTime); - ftm = FILETIME2d_time(&filefindbuf.ftLastWriteTime); - } + HANDLE findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); + ftc = FILETIME2d_time(&filefindbuf.ftCreationTime); + fta = FILETIME2d_time(&filefindbuf.ftLastAccessTime); + ftm = FILETIME2d_time(&filefindbuf.ftLastWriteTime); if (findhndl == cast(HANDLE)-1) { @@ -702,24 +654,11 @@ else void getTimes(C)(in C[] name, { version(Windows) { - HANDLE findhndl = void; - - if(useWfuncs) - { - WIN32_FIND_DATAW filefindbuf; - - findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); - fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); - fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); - } - else - { - WIN32_FIND_DATA filefindbuf; + WIN32_FIND_DATAW filefindbuf; - findhndl = FindFirstFileA(toMBSz(name), &filefindbuf); - fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); - fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); - } + HANDLE findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); + fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); + fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); enforce(findhndl != cast(HANDLE)-1, new FileException(name.idup)); @@ -814,26 +753,12 @@ else version(Windows) void getTimesWin(in char[] name, out SysTime fileAccessTime, out SysTime fileModificationTime) { - HANDLE findhndl = void; - - if (useWfuncs) - { - WIN32_FIND_DATAW filefindbuf; - - findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); - fileCreationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftCreationTime); - fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); - fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); - } - else - { - WIN32_FIND_DATA filefindbuf; + WIN32_FIND_DATAW filefindbuf; - findhndl = FindFirstFileA(toMBSz(name), &filefindbuf); - fileCreationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftCreationTime); - fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); - fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); - } + HANDLE findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); + fileCreationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftCreationTime); + fileAccessTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastAccessTime); + fileModificationTime = std.datetime.FILETIMEToSysTime(&filefindbuf.ftLastWriteTime); if(findhndl == cast(HANDLE)-1) { @@ -1127,12 +1052,9 @@ unittest { version(Windows) { - auto result = useWfuncs // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ // fileio/base/getfileattributes.asp - ? GetFileAttributesW(std.utf.toUTF16z(name)) - : GetFileAttributesA(toMBSz(name)); - return result != 0xFFFFFFFF; + return GetFileAttributesW(std.utf.toUTF16z(name)) != 0xFFFFFFFF; } else version(Posix) { @@ -1172,9 +1094,7 @@ uint getAttributes(in char[] name) { version(Windows) { - auto result = useWfuncs ? - GetFileAttributesW(std.utf.toUTF16z(name)) : - GetFileAttributesA(toMBSz(name)); + immutable result = GetFileAttributesW(std.utf.toUTF16z(name)); enforce(result != uint.max, new FileException(name.idup)); @@ -1670,9 +1590,7 @@ void chdir(in char[] pathname) { version(Windows) { - enforce(useWfuncs - ? SetCurrentDirectoryW(std.utf.toUTF16z(pathname)) - : SetCurrentDirectoryA(toMBSz(pathname)), + enforce(SetCurrentDirectoryW(std.utf.toUTF16z(pathname)), new FileException(pathname.idup)); } else version(Posix) @@ -1691,9 +1609,7 @@ void mkdir(in char[] pathname) { version(Windows) { - enforce(useWfuncs - ? CreateDirectoryW(std.utf.toUTF16z(pathname), null) - : CreateDirectoryA(toMBSz(pathname), null), + enforce(CreateDirectoryW(std.utf.toUTF16z(pathname), null), new FileException(pathname.idup)); } else version(Posix) @@ -1757,9 +1673,7 @@ void rmdir(in char[] pathname) { version(Windows) { - cenforce(useWfuncs - ? RemoveDirectoryW(std.utf.toUTF16z(pathname)) - : RemoveDirectoryA(toMBSz(pathname)), + cenforce(RemoveDirectoryW(std.utf.toUTF16z(pathname)), pathname); } else version(Posix) @@ -1916,47 +1830,21 @@ version(Windows) string getcwd() 3. the buffer (lpBuffer) is not large enough: the required size of the buffer, in characters, including the null-terminating character. */ - ushort[4096] staticBuff = void; //enough for most common case - if (useWfuncs) + wchar[4096] buffW = void; //enough for most common case + immutable n = cenforce(GetCurrentDirectoryW(to!DWORD(buffW.length), buffW.ptr), + "getcwd"); + // we can do it because toUTFX always produces a fresh string + if(n < buffW.length) { - auto buffW = cast(wchar[]) staticBuff; - immutable n = cenforce(GetCurrentDirectoryW(to!DWORD(buffW.length), buffW.ptr), - "getcwd"); - // we can do it because toUTFX always produces a fresh string - if(n < buffW.length) - { - return toUTF8(buffW[0 .. n]); - } - else //staticBuff isn't enough - { - auto ptr = cast(wchar*) malloc(wchar.sizeof * n); - scope(exit) free(ptr); - immutable n2 = GetCurrentDirectoryW(n, ptr); - cenforce(n2 && n2 < n, "getcwd"); - return toUTF8(ptr[0 .. n2]); - } + return toUTF8(buffW[0 .. n]); } - else + else //staticBuff isn't enough { - auto buffA = cast(char[]) staticBuff; - immutable n = cenforce(GetCurrentDirectoryA(to!DWORD(buffA.length), buffA.ptr), - "getcwd"); - // fromMBSz doesn't always produce a fresh string - if(n < buffA.length) - { - string res = fromMBSz(cast(immutable)buffA.ptr); - return res.ptr == buffA.ptr ? res.idup : res; - } - else //staticBuff isn't enough - { - auto ptr = cast(char*) malloc(char.sizeof * n); - scope(exit) free(ptr); - immutable n2 = GetCurrentDirectoryA(n, ptr); - cenforce(n2 && n2 < n, "getcwd"); - - string res = fromMBSz(cast(immutable)ptr); - return res.ptr == ptr ? res.idup : res; - } + auto ptr = cast(wchar*) malloc(wchar.sizeof * n); + scope(exit) free(ptr); + immutable n2 = GetCurrentDirectoryW(n, ptr); + cenforce(n2 && n2 < n, "getcwd"); + return toUTF8(ptr[0 .. n2]); } } @@ -2270,41 +2158,22 @@ else version(Windows) void _init(in char[] path) { - HANDLE findhndl = void; - uint resulth = void; - uint resultl = void; _name = path.idup; //FindFirstFileX can't handle file names which end in a backslash. if(_name.endsWith(sep)) _name.popBackN(sep.length); - if(useWfuncs) - { - WIN32_FIND_DATAW fd; + WIN32_FIND_DATAW fd; - findhndl = FindFirstFileW(std.utf.toUTF16z(_name), &fd); - enforce(findhndl != INVALID_HANDLE_VALUE); + HANDLE findhndl = FindFirstFileW(std.utf.toUTF16z(_name), &fd); + enforce(findhndl != INVALID_HANDLE_VALUE); - _size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; - _timeCreated = std.datetime.FILETIMEToSysTime(&fd.ftCreationTime); - _timeLastAccessed = std.datetime.FILETIMEToSysTime(&fd.ftLastAccessTime); - _timeLastModified = std.datetime.FILETIMEToSysTime(&fd.ftLastWriteTime); - _attributes = fd.dwFileAttributes; - } - else - { - WIN32_FIND_DATA fd; - - findhndl = FindFirstFileA(toMBSz(_name), &fd); - enforce(findhndl != INVALID_HANDLE_VALUE); - - _size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; - _timeCreated = std.datetime.FILETIMEToSysTime(&fd.ftCreationTime); - _timeLastAccessed = std.datetime.FILETIMEToSysTime(&fd.ftLastAccessTime); - _timeLastModified = std.datetime.FILETIMEToSysTime(&fd.ftLastWriteTime); - _attributes = fd.dwFileAttributes; - } + _size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; + _timeCreated = std.datetime.FILETIMEToSysTime(&fd.ftCreationTime); + _timeLastAccessed = std.datetime.FILETIMEToSysTime(&fd.ftLastAccessTime); + _timeLastModified = std.datetime.FILETIMEToSysTime(&fd.ftLastWriteTime); + _attributes = fd.dwFileAttributes; cenforce(findhndl != cast(HANDLE)-1 && FindClose(findhndl), _name); } @@ -2655,9 +2524,7 @@ void copy(in char[] from, in char[] to) { version(Windows) { - immutable result = useWfuncs - ? CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false) - : CopyFileA(toMBSz(from), toMBSz(to), false); + immutable result = CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false); if (!result) throw new FileException(to.idup); } @@ -2735,9 +2602,7 @@ else deprecated void setTimes(C)(in C[] name, d_time fta, d_time ftm) alias TypeTuple!(GENERIC_WRITE, 0, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, HANDLE.init) defaults; - auto h = useWfuncs - ? CreateFileW(std.utf.toUTF16z(name), defaults) - : CreateFileA(toMBSz(name), defaults); + auto h = CreateFileW(std.utf.toUTF16z(name), defaults); cenforce(h != INVALID_HANDLE_VALUE, name); scope(exit) cenforce(CloseHandle(h), name); @@ -2787,9 +2652,7 @@ else void setTimes(C)(in C[] name, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, HANDLE.init) defaults; - auto h = useWfuncs ? - CreateFileW(std.utf.toUTF16z(name), defaults) : - CreateFileA(toMBSz(name), defaults); + auto h = CreateFileW(std.utf.toUTF16z(name), defaults); cenforce(h != INVALID_HANDLE_VALUE, name); @@ -2994,41 +2857,19 @@ private struct DirIteratorImpl bool stepIn(string directory) { string search_pattern = buildPath(directory, "*.*"); - if(useWfuncs) - { - WIN32_FIND_DATAW findinfo; - HANDLE h = FindFirstFileW(toUTF16z(search_pattern), &findinfo); - cenforce(h != INVALID_HANDLE_VALUE, directory); - _stack.put(DirHandle(directory, h)); - return toNext(false, &findinfo); - } - else - { - WIN32_FIND_DATA findinfo; - HANDLE h = FindFirstFileA(toMBSz(search_pattern), &findinfo); - cenforce(h != INVALID_HANDLE_VALUE, directory); - _stack.put(DirHandle(directory, h)); - return toNext(false, &findinfo); - } + WIN32_FIND_DATAW findinfo; + HANDLE h = FindFirstFileW(toUTF16z(search_pattern), &findinfo); + cenforce(h != INVALID_HANDLE_VALUE, directory); + _stack.put(DirHandle(directory, h)); + return toNext(false, &findinfo); } bool next() { if(_stack.data.empty) return false; - bool result; - if (useWfuncs) - { - WIN32_FIND_DATAW findinfo; - result = toNext(true, &findinfo); - - } - else - { - WIN32_FIND_DATA findinfo; - result = toNext(true, &findinfo); - } - return result; + WIN32_FIND_DATAW findinfo; + return toNext(true, &findinfo); } bool toNext(bool fetch, WIN32_FIND_DATAW* findinfo) @@ -3813,59 +3654,29 @@ version(Windows) DirEntry de; auto c = buildPath(pathname, "*.*"); - if(useWfuncs) - { - WIN32_FIND_DATAW fileinfo; + WIN32_FIND_DATAW fileinfo; - auto h = FindFirstFileW(std.utf.toUTF16z(c), &fileinfo); - if(h == INVALID_HANDLE_VALUE) - return; - - scope(exit) FindClose(h); - - do - { - // Skip "." and ".." - if(std.string.wcscmp(fileinfo.cFileName.ptr, ".") == 0 || - std.string.wcscmp(fileinfo.cFileName.ptr, "..") == 0) - { - continue; - } - - de._init(pathname, &fileinfo); + auto h = FindFirstFileW(std.utf.toUTF16z(c), &fileinfo); + if(h == INVALID_HANDLE_VALUE) + return; - if(!callback(&de)) - break; + scope(exit) FindClose(h); - } while(FindNextFileW(h, &fileinfo) != FALSE); - } - else + do { - WIN32_FIND_DATA fileinfo; - - auto h = FindFirstFileA(toMBSz(c), &fileinfo); - - if(h == INVALID_HANDLE_VALUE) - return; - - scope(exit) FindClose(h); - - do + // Skip "." and ".." + if(std.string.wcscmp(fileinfo.cFileName.ptr, ".") == 0 || + std.string.wcscmp(fileinfo.cFileName.ptr, "..") == 0) { - // Skip "." and ".." - if(core.stdc.string.strcmp(fileinfo.cFileName.ptr, ".") == 0 || - core.stdc.string.strcmp(fileinfo.cFileName.ptr, "..") == 0) - { - continue; - } + continue; + } - de._init(pathname, &fileinfo); + de._init(pathname, &fileinfo); - if(!callback(&de)) - break; + if(!callback(&de)) + break; - } while(FindNextFileA(h, &fileinfo) != FALSE); - } + } while(FindNextFileW(h, &fileinfo) != FALSE); } } else version(Posix) diff --git a/std/mmfile.d b/std/mmfile.d index 603ac193c17..79ac72fe1e5 100644 --- a/std/mmfile.d +++ b/std/mmfile.d @@ -240,28 +240,14 @@ class MmFile if (filename) { - if (useWfuncs) - { - auto namez = std.utf.toUTF16z(filename); - hFile = CreateFileW(namez, - dwDesiredAccess2, - dwShareMode, - null, - dwCreationDisposition, - FILE_ATTRIBUTE_NORMAL, - cast(HANDLE)null); - } - else - { - auto namez = std.file.toMBSz(filename); - hFile = CreateFileA(namez, - dwDesiredAccess2, - dwShareMode, - null, - dwCreationDisposition, - FILE_ATTRIBUTE_NORMAL, - cast(HANDLE)null); - } + auto namez = std.utf.toUTF16z(filename); + hFile = CreateFileW(namez, + dwDesiredAccess2, + dwShareMode, + null, + dwCreationDisposition, + FILE_ATTRIBUTE_NORMAL, + cast(HANDLE)null); if (hFile == INVALID_HANDLE_VALUE) goto err1; } diff --git a/std/stream.d b/std/stream.d index 416076db7d2..ee2c78255d7 100644 --- a/std/stream.d +++ b/std/stream.d @@ -1855,13 +1855,8 @@ class File: Stream { readable = cast(bool)(mode & FileMode.In); writeable = cast(bool)(mode & FileMode.Out); version (Windows) { - if (std.file.useWfuncs) { - hFile = CreateFileW(std.utf.toUTF16z(filename), access, share, - null, createMode, 0, null); - } else { - hFile = CreateFileA(std.file.toMBSz(filename), access, share, - null, createMode, 0, null); - } + hFile = CreateFileW(std.utf.toUTF16z(filename), access, share, + null, createMode, 0, null); isopen = hFile != INVALID_HANDLE_VALUE; } version (Posix) { @@ -1954,9 +1949,9 @@ class File: Stream { override size_t readBlock(void* buffer, size_t size) { assertReadable(); version (Windows) { - auto dwSize = to!DWORD(size); + auto dwSize = to!DWORD(size); ReadFile(hFile, buffer, dwSize, &dwSize, null); - size = dwSize; + size = dwSize; } else version (Posix) { size = core.sys.posix.unistd.read(hFile, buffer, size); if (size == -1) @@ -1969,9 +1964,9 @@ class File: Stream { override size_t writeBlock(const void* buffer, size_t size) { assertWriteable(); version (Windows) { - auto dwSize = to!DWORD(size); + auto dwSize = to!DWORD(size); WriteFile(hFile, buffer, dwSize, &dwSize, null); - size = dwSize; + size = dwSize; } else version (Posix) { size = core.sys.posix.unistd.write(hFile, buffer, size); if (size == -1) diff --git a/std/windows/registry.d b/std/windows/registry.d index c6875357e1d..5fa4b1eb4dd 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -45,7 +45,6 @@ import std.windows.syserror; import std.windows.charset: toMBSz, fromMBSz; import std.conv; import std.utf : toUTFz, toUTF16z, toUTF8, toUTF16; -import std.__fileinit : useWfuncs; private import std.internal.windows.advapi32; //debug = winreg; @@ -327,14 +326,9 @@ in body { HKEY hkeyResult; - enforceSucc( - useWfuncs ? RegCreateKeyExW( + enforceSucc(RegCreateKeyExW( hkey, toUTF16z(subKey), 0, null, dwOptions, compatibleRegsam(samDesired), cast(LPSECURITY_ATTRIBUTES) lpsa, - &hkeyResult, &disposition) - : RegCreateKeyExA( - hkey, toMBSz(subKey), 0, null, dwOptions, - compatibleRegsam(samDesired), cast(LPSECURITY_ATTRIBUTES) lpsa, &hkeyResult, &disposition), "Failed to create requested key: \"" ~ subKey ~ "\""); @@ -353,15 +347,11 @@ body if (haveWoW64Job(samDesired)) { loadAdvapi32(); - res = - useWfuncs ? pRegDeleteKeyExW(hkey, toUTF16z(subKey), samDesired, 0) - : pRegDeleteKeyExA(hkey, toMBSz(subKey), samDesired, 0); + res = pRegDeleteKeyExW(hkey, toUTF16z(subKey), samDesired, 0); } else { - res = - useWfuncs ? RegDeleteKeyW(hkey, toUTF16z(subKey)) - : RegDeleteKeyA(hkey, toMBSz(subKey)); + res = RegDeleteKeyW(hkey, toUTF16z(subKey)); } enforceSucc(res, "Value cannot be deleted: \"" ~ subKey ~ "\""); } @@ -374,9 +364,7 @@ in } body { - enforceSucc( - useWfuncs ? RegDeleteValueW(hkey, toUTF16z(valueName)) - : RegDeleteValueA(hkey, toMBSz(valueName)), + enforceSucc(RegDeleteValueW(hkey, toUTF16z(valueName)), "Value cannot be deleted: \"" ~ valueName ~ "\""); } @@ -409,9 +397,7 @@ body } HKEY hkeyDup; - immutable res = - useWfuncs ? RegOpenKeyW(hkey, null, &hkeyDup) - : RegOpenKeyA(hkey, null, &hkeyDup); + immutable res = RegOpenKeyW(hkey, null, &hkeyDup); debug(winreg) { @@ -527,9 +513,7 @@ in body { REG_VALUE_TYPE type; - enforceSucc( - useWfuncs ? RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, null, null) - : RegQueryValueExA(hkey, toMBSz(name), null, cast(LPDWORD) &type, null, null), + enforceSucc(RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, null, null), "Value cannot be opened: \"" ~ name ~ "\""); return type; @@ -544,9 +528,7 @@ in body { HKEY hkeyResult; - enforceSucc( - useWfuncs ? RegOpenKeyExW(hkey, toUTF16z(subKey), 0, compatibleRegsam(samDesired), &hkeyResult) - : RegOpenKeyExA(hkey, toMBSz(subKey), 0, compatibleRegsam(samDesired), &hkeyResult), + enforceSucc(RegOpenKeyExW(hkey, toUTF16z(subKey), 0, compatibleRegsam(samDesired), &hkeyResult), "Failed to open requested key: \"" ~ subKey ~ "\""); return hkeyResult; @@ -586,8 +568,7 @@ body return res; } - enforceSucc( - useWfuncs ? queryValue!wchar() : queryValue!char(), + enforceSucc(queryValue!wchar(), "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); @@ -596,24 +577,12 @@ body { case REG_VALUE_TYPE.REG_SZ: case REG_VALUE_TYPE.REG_EXPAND_SZ: - if (useWfuncs) - { - auto wstr = (cast(immutable(wchar)*)data)[0 .. cbData / wchar.sizeof]; - assert(wstr.length > 0 && wstr[$-1] == '\0'); - if (wstr.length && wstr[$-1] == '\0') - wstr.length = wstr.length - 1; - assert(wstr.length == 0 || wstr[$-1] != '\0'); - value = toUTF8(wstr); - } - else - { - auto cstr = (cast(immutable(char)*)data)[0 .. cbData]; - assert(cstr.length > 0 && cstr[$-1] == '\0'); - assert(cstr.length == 1 || cstr[$-2] != '\0'); - value = fromMBSz(cstr.ptr); - if (value.ptr == cast(immutable(char)*)&u.qw) - value = value.idup; // don't point into the stack - } + auto wstr = (cast(immutable(wchar)*)data)[0 .. cbData / wchar.sizeof]; + assert(wstr.length > 0 && wstr[$-1] == '\0'); + if (wstr.length && wstr[$-1] == '\0') + wstr.length = wstr.length - 1; + assert(wstr.length == 0 || wstr[$-1] != '\0'); + value = toUTF8(wstr); break; case REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN: @@ -691,7 +660,7 @@ body } } - useWfuncs ? queryValue!wchar() : queryValue!char(); + queryValue!wchar(); } private void regQueryValue(in HKEY hkey, in string name, out uint value, REG_VALUE_TYPE reqType) @@ -704,9 +673,7 @@ body REG_VALUE_TYPE type; DWORD cbData = value.sizeof; - enforceSucc( - useWfuncs ? RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, &value, &cbData) - : RegQueryValueExA(hkey, toMBSz(name), null, cast(LPDWORD) &type, &value, &cbData), + enforceSucc(RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, &value, &cbData), "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); @@ -742,9 +709,7 @@ body REG_VALUE_TYPE type; DWORD cbData = value.sizeof; - enforceSucc( - useWfuncs ? RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, &value, &cbData) - : RegQueryValueExA(hkey, toMBSz(name), null, cast(LPDWORD) &type, &value, &cbData), + enforceSucc(RegQueryValueExW(hkey, toUTF16z(name), null, cast(LPDWORD) &type, &value, &cbData), "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); @@ -771,25 +736,12 @@ body byte[] data = new byte[100]; DWORD cbData = to!DWORD(data.length); LONG res; - if (useWfuncs) + auto keyname = toUTF16z(name); + res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); + if (res == ERROR_MORE_DATA) { - auto keyname = toUTF16z(name); + data.length = cbData; res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - if (res == ERROR_MORE_DATA) - { - data.length = cbData; - res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - } - } - else - { - auto keyname = toMBSz(name); - res = RegQueryValueExA(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - if (res == ERROR_MORE_DATA) - { - data.length = cbData; - res = RegQueryValueExA(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - } } enforceSucc(res, "Cannot read the requested value"); enforce(type == reqType, @@ -814,9 +766,7 @@ in } body { - enforceSucc( - useWfuncs ? RegSetValueExW(hkey, toUTF16z(subKey), 0, type, cast(BYTE*) lpData, cbData) - : RegSetValueExA(hkey, toMBSz(subKey), 0, type, cast(BYTE*) lpData, cbData), + enforceSucc(RegSetValueExW(hkey, toUTF16z(subKey), 0, type, cast(BYTE*) lpData, cbData), "Value cannot be set: \"" ~ subKey ~ "\""); } @@ -847,7 +797,7 @@ private void regProcessNthKey(HKEY hkey, scope void delegate(scope LONG delegate }); } - useWfuncs ? impl!wchar() : impl!char(); + impl!wchar(); } private void regProcessNthValue(HKEY hkey, scope void delegate(scope LONG delegate(DWORD, out string)) dg) @@ -877,7 +827,7 @@ private void regProcessNthValue(HKEY hkey, scope void delegate(scope LONG delega }); } - useWfuncs ? impl!wchar() : impl!char(); + impl!wchar(); } /* ************* public classes *************** */ @@ -927,9 +877,7 @@ public: { uint cSubKeys; uint cchSubKeyMaxLen; - enforceSucc( - useWfuncs ? regGetNumSubKeys!wchar(m_hkey, cSubKeys, cchSubKeyMaxLen) - : regGetNumSubKeys!char(m_hkey, cSubKeys, cchSubKeyMaxLen), + enforceSucc(regGetNumSubKeys!wchar(m_hkey, cSubKeys, cchSubKeyMaxLen), "Number of sub-keys cannot be determined"); return cSubKeys; @@ -958,9 +906,7 @@ public: { uint cValues; uint cchValueMaxLen; - enforceSucc( - useWfuncs ? regGetNumValues!wchar(m_hkey, cValues, cchValueMaxLen) - : regGetNumValues!char(m_hkey, cValues, cchValueMaxLen), + enforceSucc(regGetNumValues!wchar(m_hkey, cValues, cchValueMaxLen), "Number of values cannot be determined"); return cValues; @@ -1174,20 +1120,9 @@ public: */ void setValue(string name, string value, bool asEXPAND_SZ) { - const(void)* data; - DWORD len; - if (useWfuncs) - { - auto psz = toUTF16z(value); - data = psz; - len = to!DWORD(lstrlenW(psz) * wchar.sizeof); - } - else - { - auto psz = toMBSz(value); - data = psz; - len = lstrlenA(psz); - } + auto psz = toUTF16z(value); + const(void)* data = psz; + DWORD len = to!DWORD(lstrlenW(psz) * wchar.sizeof); regSetValue(m_hkey, name, asEXPAND_SZ ? REG_VALUE_TYPE.REG_EXPAND_SZ @@ -1216,24 +1151,7 @@ public: data[$-1] = "\0"; auto ws = std.array.join(data, "\0"w); - if (useWfuncs) - { - regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_MULTI_SZ, ws.ptr, to!uint(ws.length * wchar.sizeof)); - } - else - { - char[] cs; - int readLen; - cs.length = WideCharToMultiByte(/*CP_ACP*/ 0, 0, ws.ptr, to!uint(ws.length), null, 0, null, null); - if (cs.length) - { - readLen = WideCharToMultiByte(/*CP_ACP*/ 0, 0, ws.ptr, to!uint(ws.length), cs.ptr, to!int(cs.length), null, null); - } - enforce(readLen && readLen == cs.length, - new Win32Exception("Couldn't convert string: " ~ sysErrorString(GetLastError()))); - - regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_MULTI_SZ, cs.ptr, to!uint(cs.length)); - } + regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_MULTI_SZ, ws.ptr, to!uint(ws.length * wchar.sizeof)); } /** @@ -1880,39 +1798,30 @@ unittest debug(winreg) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(winreg) writefln("std.windows.registry.unittest read"); - auto save_useWfuncs = useWfuncs; - scope(exit) useWfuncs = save_useWfuncs; - - foreach (loop; 0..2) - { - if (loop == 0) useWfuncs = false; - else useWfuncs = true; - /+ - // Mask for test speed up + // Mask for test speed up - Key HKCR = Registry.classesRoot; - Key CLSID = HKCR.getKey("CLSID"); + Key HKCR = Registry.classesRoot; + Key CLSID = HKCR.getKey("CLSID"); - foreach (Key key; CLSID.keys) + foreach (Key key; CLSID.keys) + { + foreach (Value val; key.values) { - foreach (Value val; key.values) - { - } } + } +/ - Key HKCU = Registry.currentUser; - assert(HKCU); + Key HKCU = Registry.currentUser; + assert(HKCU); - // Enumerate all subkeys of key Software - Key softwareKey = HKCU.getKey("Software"); - assert(softwareKey); - foreach (Key key; softwareKey.keys) + // Enumerate all subkeys of key Software + Key softwareKey = HKCU.getKey("Software"); + assert(softwareKey); + foreach (Key key; softwareKey.keys) + { + //writefln("Key %s", key.name); + foreach (Value val; key.values) { - //writefln("Key %s", key.name); - foreach (Value val; key.values) - { - } } } } @@ -1922,74 +1831,62 @@ unittest debug(winreg) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(winreg) writefln("std.windows.registry.unittest write"); - auto save_useWfuncs = useWfuncs; - scope(exit) useWfuncs = save_useWfuncs; - - foreach (loop; 0..2) - { - if (loop == 0) useWfuncs = false; - else useWfuncs = true; - - if (useWfuncs == false) - continue; - - // Warning: This unit test writes to the registry. - // The test can fail if you don't have sufficient rights - - Key HKCU = Registry.currentUser; - assert(HKCU); - - // Create a new key - string unittestKeyName = "Temporary key for a D UnitTest which can be deleted afterwards"; - Key unittestKey = HKCU.createKey(unittestKeyName); - assert(unittestKey); - Key cityKey = unittestKey.createKey("CityCollection using foreign names with umlauts and accents: \u00f6\u00e4\u00fc\u00d6\u00c4\u00dc\u00e0\u00e1\u00e2\u00df"); - cityKey.setValue("K\u00f6ln", "Germany"); // Cologne - cityKey.setValue("\u041c\u0438\u043d\u0441\u043a", "Belarus"); // Minsk - cityKey.setValue("\u5317\u4eac", "China"); // Bejing - bool foundCologne, foundMinsk, foundBeijing; - foreach (Value v; cityKey.values) + // Warning: This unit test writes to the registry. + // The test can fail if you don't have sufficient rights + + Key HKCU = Registry.currentUser; + assert(HKCU); + + // Create a new key + string unittestKeyName = "Temporary key for a D UnitTest which can be deleted afterwards"; + Key unittestKey = HKCU.createKey(unittestKeyName); + assert(unittestKey); + Key cityKey = unittestKey.createKey("CityCollection using foreign names with umlauts and accents: \u00f6\u00e4\u00fc\u00d6\u00c4\u00dc\u00e0\u00e1\u00e2\u00df"); + cityKey.setValue("K\u00f6ln", "Germany"); // Cologne + cityKey.setValue("\u041c\u0438\u043d\u0441\u043a", "Belarus"); // Minsk + cityKey.setValue("\u5317\u4eac", "China"); // Bejing + bool foundCologne, foundMinsk, foundBeijing; + foreach (Value v; cityKey.values) + { + auto vname = v.name; + auto vvalue_SZ = v.value_SZ; + if (v.name == "K\u00f6ln") { - auto vname = v.name; - auto vvalue_SZ = v.value_SZ; - if (v.name == "K\u00f6ln") - { - foundCologne = true; - assert(v.value_SZ == "Germany"); - } - if (v.name == "\u041c\u0438\u043d\u0441\u043a") - { - foundMinsk = true; - assert(v.value_SZ == "Belarus"); - } - if (v.name == "\u5317\u4eac") - { - foundBeijing = true; - assert(v.value_SZ == "China"); - } + foundCologne = true; + assert(v.value_SZ == "Germany"); + } + if (v.name == "\u041c\u0438\u043d\u0441\u043a") + { + foundMinsk = true; + assert(v.value_SZ == "Belarus"); + } + if (v.name == "\u5317\u4eac") + { + foundBeijing = true; + assert(v.value_SZ == "China"); } - assert(foundCologne); - assert(foundMinsk); - assert(foundBeijing); - - Key stateKey = unittestKey.createKey("StateCollection"); - stateKey.setValue("Germany", ["D\u00fcsseldorf", "K\u00f6ln", "Hamburg"]); - Value v = stateKey.getValue("Germany"); - string[] actual = v.value_MULTI_SZ; - assert(actual.length == 3); - assert(actual[0] == "D\u00fcsseldorf"); - assert(actual[1] == "K\u00f6ln"); - assert(actual[2] == "Hamburg"); - - Key numberKey = unittestKey.createKey("Number"); - numberKey.setValue("One", 1); - Value one = numberKey.getValue("One"); - assert(one.value_SZ == "1"); - assert(one.value_DWORD == 1); - - unittestKey.deleteKey(numberKey.name); - unittestKey.deleteKey(stateKey.name); - unittestKey.deleteKey(cityKey.name); - HKCU.deleteKey(unittestKeyName); } + assert(foundCologne); + assert(foundMinsk); + assert(foundBeijing); + + Key stateKey = unittestKey.createKey("StateCollection"); + stateKey.setValue("Germany", ["D\u00fcsseldorf", "K\u00f6ln", "Hamburg"]); + Value v = stateKey.getValue("Germany"); + string[] actual = v.value_MULTI_SZ; + assert(actual.length == 3); + assert(actual[0] == "D\u00fcsseldorf"); + assert(actual[1] == "K\u00f6ln"); + assert(actual[2] == "Hamburg"); + + Key numberKey = unittestKey.createKey("Number"); + numberKey.setValue("One", 1); + Value one = numberKey.getValue("One"); + assert(one.value_SZ == "1"); + assert(one.value_DWORD == 1); + + unittestKey.deleteKey(numberKey.name); + unittestKey.deleteKey(stateKey.name); + unittestKey.deleteKey(cityKey.name); + HKCU.deleteKey(unittestKeyName); } diff --git a/win32.mak b/win32.mak index f105860bea4..553d4de736e 100644 --- a/win32.mak +++ b/win32.mak @@ -126,7 +126,6 @@ SRCS_3 = std\variant.d \ std\stream.d std\socket.d std\socketstream.d \ std\perf.d std\container.d std\conv.d \ std\zip.d std\cstream.d std\loader.d \ - std\__fileinit.d \ std\datebase.d \ std\regex.d \ std\stdarg.d \ @@ -280,7 +279,7 @@ SRC_STD= std\zlib.d std\zip.d std\stdint.d std\container.d std\conv.d std\utf.d std\json.d std\xml.d std\encoding.d std\bigint.d std\concurrency.d \ std\range.d std\stdiobase.d std\parallelism.d \ std\regex.d std\datebase.d \ - std\__fileinit.d std\gregorian.d std\exception.d std\ascii.d + std\gregorian.d std\exception.d std\ascii.d SRC_STD_NET= std\net\isemail.d std\net\curl.d @@ -452,9 +451,6 @@ exception.obj : std\exception.d file.obj : std\file.d $(DMD) -c $(DFLAGS) std\file.d -__fileinit.obj : std\__fileinit.d - $(DMD) -c $(DFLAGS) std\__fileinit.d - format.obj : std\format.d $(DMD) -c $(DFLAGS) std\format.d From f01bcb71f5dca26f8a69f1487b42954012db6ded Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Tue, 24 Jan 2012 21:34:52 +0400 Subject: [PATCH 07/33] Remove unnecessary stuff from std.windows.registry * remove stuff which have become unnecessary because of previous commit from std.windows.registry --- std/windows/registry.d | 215 ++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 143 deletions(-) diff --git a/std/windows/registry.d b/std/windows/registry.d index 5fa4b1eb4dd..d0eae295010 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -52,23 +52,6 @@ debug(winreg) import std.stdio; private { - template SelUni(alias Asym, alias Wsym) - { - template SelUni(Char) - { - static if (is(Char == char)) - { - alias Asym SelUni; - } - else - { - static assert (is(Char == wchar)); - alias Wsym SelUni; - } - } - } - - extern (Windows) int lstrlenA(LPCSTR lpString); extern (Windows) int lstrlenW(LPCWSTR lpString); void enforceSucc(LONG res, lazy string message, string fn = __FILE__, size_t ln = __LINE__) @@ -412,7 +395,7 @@ body return (res == ERROR_SUCCESS) ? hkeyDup : null; } -private LONG regEnumKeyName(Char)(in HKEY hkey, in DWORD index, ref Char[] name, out DWORD cchName) +private LONG regEnumKeyName(in HKEY hkey, in DWORD index, ref wchar[] name, out DWORD cchName) in { assert(hkey !is null); @@ -425,15 +408,13 @@ out(res) } body { - alias SelUni!(RegEnumKeyExA, RegEnumKeyExW) RegEnumKeyEx; - // The Registry API lies about the lengths of a very few sub-key lengths // so we have to test to see if it whinges about more data, and provide // more if it does. for (;;) { cchName = to!DWORD(name.length); - immutable res = RegEnumKeyEx!Char(hkey, index, name.ptr, &cchName, null, null, null, null); + immutable res = RegEnumKeyExW(hkey, index, name.ptr, &cchName, null, null, null, null); if (res != ERROR_MORE_DATA) return res; @@ -445,19 +426,17 @@ body } -private LONG regEnumValueName(Char)(in HKEY hkey, in DWORD dwIndex, ref Char[] name, out DWORD cchName) +private LONG regEnumValueName(in HKEY hkey, in DWORD dwIndex, ref wchar[] name, out DWORD cchName) in { assert(hkey !is null); } body { - alias SelUni!(RegEnumValueA, RegEnumValueW) RegEnumValue; - for (;;) { cchName = to!DWORD(name.length); - immutable res = RegEnumValue!Char(hkey, dwIndex, name.ptr, &cchName, null, null, null, null); + immutable res = RegEnumValueW(hkey, dwIndex, name.ptr, &cchName, null, null, null, null); if (res != ERROR_MORE_DATA) return res; @@ -467,42 +446,26 @@ body assert(0); } -private LONG regGetNumSubKeys(Char)(in HKEY hkey, out DWORD cSubKeys, out DWORD cchSubKeyMaxLen) +private LONG regGetNumSubKeys(in HKEY hkey, out DWORD cSubKeys, out DWORD cchSubKeyMaxLen) in { assert(hkey !is null); } body { - static if (is(Char == wchar)) - { - return RegQueryInfoKeyW(hkey, null, null, null, &cSubKeys, - &cchSubKeyMaxLen, null, null, null, null, null, null); - } - else - { - return RegQueryInfoKeyA(hkey, null, null, null, &cSubKeys, - &cchSubKeyMaxLen, null, null, null, null, null, null); - } + return RegQueryInfoKeyW(hkey, null, null, null, &cSubKeys, + &cchSubKeyMaxLen, null, null, null, null, null, null); } -private LONG regGetNumValues(Char)(in HKEY hkey, out DWORD cValues, out DWORD cchValueMaxLen) +private LONG regGetNumValues(in HKEY hkey, out DWORD cValues, out DWORD cchValueMaxLen) in { assert(hkey !is null); } body { - static if (is(Char == wchar)) - { - return RegQueryInfoKeyW(hkey, null, null, null, null, null, null, - &cValues, &cchValueMaxLen, null, null, null); - } - else - { - return RegQueryInfoKeyA(hkey, null, null, null, null, null, null, - &cValues, &cchValueMaxLen, null, null, null); - } + return RegQueryInfoKeyW(hkey, null, null, null, null, null, null, + &cValues, &cchValueMaxLen, null, null, null); } private REG_VALUE_TYPE regGetValueType(in HKEY hkey, in string name) @@ -553,22 +516,15 @@ body void* data = &u.qw; DWORD cbData = u.qw.sizeof; - LONG queryValue(Char)() + auto keyname = toUTF16z(name); + LONG res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); + if (res == ERROR_MORE_DATA) { - alias SelUni!(RegQueryValueExA, RegQueryValueExW) RegQueryValueEx; - alias SelUni!(toMBSz, toUTF16z) toSTRz; - - auto keyname = toSTRz!Char(name); - LONG res = RegQueryValueEx!Char(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); - if (res == ERROR_MORE_DATA) - { - data = (new Char[cbData]).ptr; - res = RegQueryValueEx!Char(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); - } - return res; + data = (new wchar[cbData]).ptr; + res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); } - enforceSucc(queryValue!wchar(), + enforceSucc(res, "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); @@ -619,48 +575,37 @@ body { REG_VALUE_TYPE type; - void queryValue(Char)() + auto keyname = toUTF16z(name); + wchar[] data = new wchar[256]; + DWORD cbData = to!DWORD(data.length / wchar.sizeof); + LONG res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); + if (res == ERROR_MORE_DATA) { - alias SelUni!(RegQueryValueExA, RegQueryValueExW) RegQueryValueEx; - alias SelUni!(toMBSz, toUTF16z) toSTRz; + data.length = cbData / wchar.sizeof; + res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); + } + else if (res == ERROR_SUCCESS) + { + data.length = cbData / wchar.sizeof; + } + enforceSucc(res, "Cannot read the requested value"); + enforce(type == REG_VALUE_TYPE.REG_MULTI_SZ, + new RegistryException("Cannot read the given value as a string")); + enforce(type == reqType, + new RegistryException("Value type has been changed since the value was acquired")); - auto keyname = toSTRz!Char(name); - Char[] data = new Char[256]; - DWORD cbData = to!DWORD(data.length / Char.sizeof); - LONG res = RegQueryValueEx!Char(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - if (res == ERROR_MORE_DATA) - { - data.length = cbData / Char.sizeof; - res = RegQueryValueEx!Char(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); - } - else if (res == ERROR_SUCCESS) - { - data.length = cbData / Char.sizeof; - } - enforceSucc(res, "Cannot read the requested value"); - enforce(type == REG_VALUE_TYPE.REG_MULTI_SZ, - new RegistryException("Cannot read the given value as a string")); - enforce(type == reqType, - new RegistryException("Value type has been changed since the value was acquired")); - - // Remove last two (or one) null terminator - assert(data.length > 0 && data[$-1] == '\0'); + // Remove last two (or one) null terminator + assert(data.length > 0 && data[$-1] == '\0'); + data.length = data.length - 1; + if (data.length > 0 && data[$-1] == '\0') data.length = data.length - 1; - if (data.length > 0 && data[$-1] == '\0') - data.length = data.length - 1; - auto list = std.array.split(data[], "\0"); - value.length = list.length; - foreach (i, ref v; value) - { - static if (is(Char == wchar)) - v = toUTF8(list[i]); - else - v = fromMBSz(cast(immutable(char)*)list[i].ptr); // assume unique - } + auto list = std.array.split(data[], "\0"); + value.length = list.length; + foreach (i, ref v; value) + { + v = toUTF8(list[i]); } - - queryValue!wchar(); } private void regQueryValue(in HKEY hkey, in string name, out uint value, REG_VALUE_TYPE reqType) @@ -772,62 +717,46 @@ body private void regProcessNthKey(HKEY hkey, scope void delegate(scope LONG delegate(DWORD, out string)) dg) { - void impl(Char)() - { - DWORD cSubKeys; - DWORD cchSubKeyMaxLen; + DWORD cSubKeys; + DWORD cchSubKeyMaxLen; - immutable res = regGetNumSubKeys!Char(hkey, cSubKeys, cchSubKeyMaxLen); - assert(res == ERROR_SUCCESS); + immutable res = regGetNumSubKeys(hkey, cSubKeys, cchSubKeyMaxLen); + assert(res == ERROR_SUCCESS); - Char[] sName = new Char[cchSubKeyMaxLen + 1]; + wchar[] sName = new wchar[cchSubKeyMaxLen + 1]; - dg((DWORD index, out string name) + dg((DWORD index, out string name) + { + DWORD cchName; + immutable res = regEnumKeyName(hkey, index, sName, cchName); + if (res == ERROR_SUCCESS) { - DWORD cchName; - immutable res = regEnumKeyName!Char(hkey, index, sName, cchName); - if (res == ERROR_SUCCESS) - { - static if (is(Char == wchar)) - name = toUTF8(sName[0 .. cchName]); - else - name = fromMBSz(cast(immutable(char)*) sName.ptr); - } - return res; - }); - } - - impl!wchar(); + name = toUTF8(sName[0 .. cchName]); + } + return res; + }); } private void regProcessNthValue(HKEY hkey, scope void delegate(scope LONG delegate(DWORD, out string)) dg) { - void impl(Char)() - { - DWORD cValues; - DWORD cchValueMaxLen; + DWORD cValues; + DWORD cchValueMaxLen; - immutable res = regGetNumValues!Char(hkey, cValues, cchValueMaxLen); - assert(res == ERROR_SUCCESS); + immutable res = regGetNumValues(hkey, cValues, cchValueMaxLen); + assert(res == ERROR_SUCCESS); - Char[] sName = new Char[cchValueMaxLen + 1]; + wchar[] sName = new wchar[cchValueMaxLen + 1]; - dg((DWORD index, out string name) + dg((DWORD index, out string name) + { + DWORD cchName; + immutable res = regEnumValueName(hkey, index, sName, cchName); + if (res == ERROR_SUCCESS) { - DWORD cchName; - immutable res = regEnumValueName!Char(hkey, index, sName, cchName); - if (res == ERROR_SUCCESS) - { - static if (is(Char == wchar)) - name = toUTF8(sName[0 .. cchName]); - else - name = fromMBSz(cast(immutable(char)*) sName.ptr); - } - return res; - }); - } - - impl!wchar(); + name = toUTF8(sName[0 .. cchName]); + } + return res; + }); } /* ************* public classes *************** */ @@ -877,7 +806,7 @@ public: { uint cSubKeys; uint cchSubKeyMaxLen; - enforceSucc(regGetNumSubKeys!wchar(m_hkey, cSubKeys, cchSubKeyMaxLen), + enforceSucc(regGetNumSubKeys(m_hkey, cSubKeys, cchSubKeyMaxLen), "Number of sub-keys cannot be determined"); return cSubKeys; @@ -906,7 +835,7 @@ public: { uint cValues; uint cchValueMaxLen; - enforceSucc(regGetNumValues!wchar(m_hkey, cValues, cchValueMaxLen), + enforceSucc(regGetNumValues(m_hkey, cValues, cchValueMaxLen), "Number of values cannot be determined"); return cValues; From 4d451796fee93a63657c4fc68f74377e216e527a Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Tue, 24 Jan 2012 21:55:52 +0400 Subject: [PATCH 08/33] Fix unsafe *A function using * Supersede unsafe ExpandEnvironmentStringsA using by its *W version * Remove an outdated commented out function * Remove std.windows.charset import which have become unnecessary --- std/windows/registry.d | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/std/windows/registry.d b/std/windows/registry.d index d0eae295010..afa39a8560e 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -42,7 +42,6 @@ import std.system : Endian, endian; import std.exception; import std.c.windows.windows; import std.windows.syserror; -import std.windows.charset: toMBSz, fromMBSz; import std.conv; import std.utf : toUTFz, toUTF16z, toUTF8, toUTF16; private import std.internal.windows.advapi32; @@ -233,26 +232,6 @@ private REG_VALUE_TYPE _RVT_from_Endian(Endian endian) } } -/+ -private string expand_environment_strings(in string value) -in -{ - assert(value !is null); -} -body -{ - LPCSTR lpSrc = toMBSz(value); - DWORD cchRequired = ExpandEnvironmentStringsA(lpSrc, null, 0); - char[] newValue = new char[cchRequired]; - - if (!ExpandEnvironmentStringsA(lpSrc, newValue, newValue.length)) - throw new Win32Exception("Failed to expand environment variables"); - - return newValue; -} -+/ - - private LONG regCloseKey(in HKEY hkey) in { @@ -1200,19 +1179,17 @@ public: { string value = value_SZ; - // value = expand_environment_strings(value); - // return value; - // ExpandEnvironemntStrings(): // http://msdn2.microsoft.com/en-us/library/ms724265.aspx - LPCSTR lpSrc = toMBSz(value); - DWORD cchRequired = ExpandEnvironmentStringsA(lpSrc, null, 0); - char[] newValue = new char[cchRequired]; + LPCWSTR lpSrc = toUTF16z(value); + DWORD cchRequired = ExpandEnvironmentStringsW(lpSrc, null, 0); + wchar[] newValue = new wchar[cchRequired]; - if (!ExpandEnvironmentStringsA(lpSrc, newValue.ptr, to!DWORD(newValue.length))) - throw new Win32Exception("Failed to expand environment variables"); + immutable DWORD count = enforceEx!Win32Exception( + ExpandEnvironmentStringsW(lpSrc, newValue.ptr, to!DWORD(newValue.length)), + "Failed to expand environment variables"); - return fromMBSz(cast(immutable(char)*) newValue.ptr); // remove trailing 0 + return toUTF8(newValue[0 .. count-1]); // remove trailing 0 } /** From 8a92201226469626b94a9c47afa9405b5ffa1e02 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Tue, 24 Jan 2012 22:48:09 +0400 Subject: [PATCH 09/33] Fix minor memory wasting in std.windows.registry --- std/windows/registry.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/windows/registry.d b/std/windows/registry.d index afa39a8560e..c6b23fa7216 100644 --- a/std/windows/registry.d +++ b/std/windows/registry.d @@ -499,7 +499,7 @@ body LONG res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); if (res == ERROR_MORE_DATA) { - data = (new wchar[cbData]).ptr; + data = (new ubyte[cbData]).ptr; res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data, &cbData); } @@ -556,7 +556,7 @@ body auto keyname = toUTF16z(name); wchar[] data = new wchar[256]; - DWORD cbData = to!DWORD(data.length / wchar.sizeof); + DWORD cbData = to!DWORD(data.length * wchar.sizeof); LONG res = RegQueryValueExW(hkey, keyname, null, cast(LPDWORD) &type, data.ptr, &cbData); if (res == ERROR_MORE_DATA) { From efc9da711c7ec5c73fd77f20be9fc5c363d12766 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Tue, 24 Jan 2012 22:54:55 +0400 Subject: [PATCH 10/33] Remove Windows 3.x and Win9x enforcements from std.mmfile --- std/mmfile.d | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/std/mmfile.d b/std/mmfile.d index 79ac72fe1e5..ff05b5f6487 100644 --- a/std/mmfile.d +++ b/std/mmfile.d @@ -32,15 +32,6 @@ version (Windows) { private import std.c.windows.windows; private import std.utf; - - private __gshared const uint dwVersion; - - shared static this() - { - /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us - /sysinfo/base/getversion.asp */ - dwVersion = GetVersion(); - } } else version (Posix) { @@ -188,12 +179,6 @@ class MmFile uint dwCreationDisposition; uint flProtect; - if (dwVersion & 0x80000000 && (dwVersion & 0xFF) == 3) - { - throw new FileException(filename, - "Win32s does not implement mm files"); - } - switch (mode) { case Mode.read: @@ -222,11 +207,6 @@ class MmFile break; case Mode.readCopyOnWrite: - if (dwVersion & 0x80000000) - { - throw new FileException(filename, - "Win9x does not implement copy on write"); - } dwDesiredAccess2 = GENERIC_READ | GENERIC_WRITE; dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; dwCreationDisposition = OPEN_EXISTING; @@ -505,11 +485,7 @@ class MmFile { debug (MMFILE) printf("MmFile.unmap()\n"); version(Windows) { - /* Note that under Windows 95, UnmapViewOfFile() seems to return - * random values, not TRUE or FALSE. - */ - errnoEnforce(!data || UnmapViewOfFile(data.ptr) != FALSE || - (dwVersion & 0x80000000) != 0); + errnoEnforce(!data || UnmapViewOfFile(data.ptr) != FALSE); } else { errnoEnforce(!data || munmap(cast(void*)data, data.length) == 0, "munmap failed"); From 90497eeededd96fe2bdcd494b7eb04dedad32f8a Mon Sep 17 00:00:00 2001 From: k-hara Date: Fri, 10 Feb 2012 21:28:45 +0900 Subject: [PATCH 11/33] Issue 7476 - Write(ln) functions no longer accept retro range --- std/range.d | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/std/range.d b/std/range.d index 6bfc3efaf14..55771ea020a 100644 --- a/std/range.d +++ b/std/range.d @@ -290,6 +290,10 @@ void put(R, E)(ref R r, E e) { r.put((&e)[0..1]); } + else static if (isInputRange!E && is(typeof(put(r, e.front)))) + { + for (; !e.empty; e.popFront()) put(r, e.front); + } else { static assert(false, @@ -396,6 +400,25 @@ unittest static assert(!__traits(compiles, put(a, "ABC"))); } +unittest +{ + // Test fix for bug 7476. + struct LockingTextWriter + { + void put(dchar c){} + } + struct RetroResult + { + bool end = false; + @property bool empty() const { return end; } + @property dchar front(){ return 'a'; } + void popFront(){ end = true; } + } + LockingTextWriter w; + RetroResult r; + put(w, r); +} + /** Returns $(D true) if $(D R) is an output range for elements of type $(D E). An output range is defined functionally as a range that From 84cefc42f4fd52425b100ebab461fe23c08fa0db Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sat, 11 Feb 2012 19:45:05 +0400 Subject: [PATCH 12/33] Add getting rid of Win9x support to changelog.dd --- changelog.dd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.dd b/changelog.dd index b29835f64e4..ab067822224 100644 --- a/changelog.dd +++ b/changelog.dd @@ -28,6 +28,8 @@ $(VERSION 058, ddd mm, 2012, =================================================, $(LI std.uni's isUniLower, isUniUpper, toUniLower, toUniUpper, and isUniAlpha have been deprecated. Please use the versions of these functions which do not have Uni in their name.) + $(LI Get rid of Windows 3.x and Windows 9x support. Affected modules: std.file, + std.mmfile, std.stream, and std.windows.registry.) ) $(LIBBUGSFIXED From e36dbeea6c338f973b24bb181a2eacca79839927 Mon Sep 17 00:00:00 2001 From: dawg Date: Mon, 13 Feb 2012 16:55:37 +0100 Subject: [PATCH 13/33] use module scope for imports... ...because the std imports in the Base class are private (see 7491). --- std/cstream.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/cstream.d b/std/cstream.d index e91319ef3af..3112b4202fe 100644 --- a/std/cstream.d +++ b/std/cstream.d @@ -96,7 +96,7 @@ class CFile : Stream { * Ditto */ override char ungetc(char c) { - return cast(char)std.c.stdio.ungetc(c,cfile); + return cast(char).std.c.stdio.ungetc(c,cfile); } /** @@ -168,14 +168,14 @@ class CFile : Stream { auto exp = "Testing stream.d:"; assert(line[0] == 'T'); assert(line.length == exp.length); - assert(!std.string.cmp(line, "Testing stream.d:")); + assert(!.std.string.cmp(line, "Testing stream.d:")); // jump over "Hello, " file.seek(7, SeekPos.Current); version (Windows) assert(file.position() == 19 + 7); version (Posix) assert(file.position() == 18 + 7); - assert(!std.string.cmp(file.readString(6), "world!")); + assert(!.std.string.cmp(file.readString(6), "world!")); i = 0; file.read(i); assert(i == 666); // string#1 + string#2 + int should give exacly that From b801b26d41866b1738b9306852ede4fb889fcda5 Mon Sep 17 00:00:00 2001 From: Jimmy Cao Date: Tue, 14 Feb 2012 23:49:32 -0600 Subject: [PATCH 14/33] Make exceptions more informative --- std/net/curl.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/net/curl.d b/std/net/curl.d index 55540066e9e..b26df2d9149 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -3339,7 +3339,7 @@ struct Curl private string errorString(CurlCode code) { - return format("%s on handle %s", curl_easy_strerror(code), handle); + return format("%s on handle %s", to!string(curl_easy_strerror(code)), handle); } private void throwOnStopped(string message = null) From 9334e2adbf83cb16b2ffb63ef828fe58dc26d8cd Mon Sep 17 00:00:00 2001 From: KennyTM~ Date: Fri, 10 Feb 2012 05:25:46 +0800 Subject: [PATCH 15/33] Make Nullable pure/nothrow/@safe/const when possible. --- std/typecons.d | 176 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 137 insertions(+), 39 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 33355c80254..354eedd6a9d 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -1168,7 +1168,7 @@ struct Nullable(T) /** Constructor initializing $(D this) with $(D value). */ - this(T value) + this()(T value) { _value = value; _isNull = false; @@ -1177,7 +1177,7 @@ Constructor initializing $(D this) with $(D value). /** Returns $(D true) if and only if $(D this) is in the null state. */ - @property bool isNull() const + @property bool isNull() const pure nothrow @safe { return _isNull; } @@ -1185,17 +1185,24 @@ Returns $(D true) if and only if $(D this) is in the null state. /** Forces $(D this) to the null state. */ - void nullify() + void nullify()() { clear(_value); _isNull = true; } + //@@@BUG4424@@@ + private mixin template _workaround4424() + { + @disable void opAssign(ref const Nullable); + } + mixin _workaround4424; + /** Assigns $(D value) to the internally-held state. If the assignment succeeds, $(D this) becomes non-null. */ - void opAssign(T value) + void opAssign()(T value) { _value = value; _isNull = false; @@ -1206,14 +1213,7 @@ Gets the value. Throws an exception if $(D this) is in the null state. This function is also called for the implicit conversion to $(D T). */ - @property ref T get() - { - enforce(!isNull); - return _value; - } - //@@@BUG3748@@@: inout does not work properly. - // need to define a separate 'const' version - @property ref const(T) get() const + @property ref inout(T) get() inout pure @safe { enforce(!isNull); return _value; @@ -1234,8 +1234,7 @@ unittest a = 5; assert(!a.isNull); assert(a == 5); - //@@@BUG5188@@@ - //assert(a != 3); + assert(a != 3); assert(a.get != 3); a.nullify(); assert(a.isNull); @@ -1243,6 +1242,8 @@ unittest assert(a == 3); a *= 6; assert(a == 18); + a = a; + assert(a == 18); a.nullify(); assertThrown(a += 2); } @@ -1272,14 +1273,44 @@ unittest assert(s.isNull); s = S(6); assert(s == S(6)); - //@@@BUG5188@@@ - //assert(s != S(0)); + assert(s != S(0)); assert(s.get != S(0)); s.x = 9190; assert(s.x == 9190); s.nullify(); assertThrown(s.x = 9441); } +unittest +{ + // Ensure Nullable can be used in pure/nothrow/@safe environment. + function() pure nothrow @safe + { + Nullable!int n; + assert(n.isNull); + n = 4; + assert(!n.isNull); + try { assert(n == 4); } catch (Exception) { assert(false); } + n.nullify(); + assert(n.isNull); + }(); +} +unittest +{ + // Ensure Nullable can be used when the value is not pure/nothrow/@safe + static struct S + { + int x; + this(this) @system {} + } + + Nullable!S s; + assert(s.isNull); + s = S(5); + assert(!s.isNull); + assert(s.x == 5); + s.nullify(); + assert(s.isNull); +} /** Just like $(D Nullable!T), except that the null state is defined as a @@ -1295,7 +1326,7 @@ struct Nullable(T, T nullValue) /** Constructor initializing $(D this) with $(D value). */ - this(T value) + this()(T value) { _value = value; } @@ -1303,7 +1334,7 @@ Constructor initializing $(D this) with $(D value). /** Returns $(D true) if and only if $(D this) is in the null state. */ - @property bool isNull() const + @property bool isNull()() const { return _value == nullValue; } @@ -1311,7 +1342,7 @@ Returns $(D true) if and only if $(D this) is in the null state. /** Forces $(D this) to the null state. */ - void nullify() + void nullify()() { _value = nullValue; } @@ -1320,7 +1351,7 @@ Forces $(D this) to the null state. Assigns $(D value) to the internally-held state. No null checks are made. */ - void opAssign(T value) + void opAssign()(T value) { _value = value; } @@ -1330,13 +1361,7 @@ Gets the value. Throws an exception if $(D this) is in the null state. This function is also called for the implicit conversion to $(D T). */ - @property ref T get() - { - enforce(!isNull); - return _value; - } - //@@@BUG3748@@@ - @property ref const(T) get() const + @property ref inout(T) get()() inout { enforce(!isNull); return _value; @@ -1378,6 +1403,39 @@ unittest a.nullify(); assert(f(a) == 42); } +unittest +{ + // Ensure Nullable can be used in pure/nothrow/@safe environment. + function() pure nothrow @safe + { + Nullable!(int, int.min) n; + pragma(msg, typeof(&n.get!())); + + assert(n.isNull); + n = 4; + assert(!n.isNull); + try { assert(n == 4); } catch (Exception) { assert(false); } + n.nullify(); + assert(n.isNull); + }(); +} +unittest +{ + // Ensure Nullable can be used when the value is not pure/nothrow/@safe + static struct S + { + int x; + bool opEquals(ref const S s) const @system { return s.x == x; } + } + + Nullable!(S, S(711)) s; + assert(s.isNull); + s = S(5); + assert(!s.isNull); + assert(s.x == 5); + s.nullify(); + assert(s.isNull); +} /** Just like $(D Nullable!T), except that the object refers to a value @@ -1392,7 +1450,7 @@ struct NullableRef(T) /** Constructor binding $(D this) with $(D value). */ - this(T * value) + this(T * value) pure nothrow @safe { _value = value; } @@ -1400,7 +1458,7 @@ Constructor binding $(D this) with $(D value). /** Binds the internal state to $(D value). */ - void bind(T * value) + void bind(T * value) pure nothrow @safe { _value = value; } @@ -1408,7 +1466,7 @@ Binds the internal state to $(D value). /** Returns $(D true) if and only if $(D this) is in the null state. */ - @property bool isNull() const + @property bool isNull() const pure nothrow @safe { return _value is null; } @@ -1416,7 +1474,7 @@ Returns $(D true) if and only if $(D this) is in the null state. /** Forces $(D this) to the null state. */ - void nullify() + void nullify() pure nothrow @safe { _value = null; } @@ -1424,7 +1482,7 @@ Forces $(D this) to the null state. /** Assigns $(D value) to the internally-held state. */ - void opAssign(T value) + void opAssign()(T value) { enforce(_value); *_value = value; @@ -1435,13 +1493,7 @@ Gets the value. Throws an exception if $(D this) is in the null state. This function is also called for the implicit conversion to $(D T). */ - @property ref T get() - { - enforce(!isNull); - return *_value; - } - //@@@BUG3748@@@ - @property ref const(T) get() const + @property ref inout(T) get()() inout { enforce(!isNull); return *_value; @@ -1486,6 +1538,52 @@ unittest a.nullify(); assert(f(a) == 42); } +unittest +{ + // Ensure NullableRef can be used in pure/nothrow/@safe environment. + function() pure nothrow @safe + { + auto storage = new int; + *storage = 19902; + NullableRef!int n; + assert(n.isNull); + n.bind(storage); + assert(!n.isNull); + try + { + assert(n == 19902); + n = 2294; + assert(n == 2294); + } + catch (Exception) + { + assert(false); + } + assert(*storage == 2294); + n.nullify(); + assert(n.isNull); + }(); +} +unittest +{ + // Ensure NullableRef can be used when the value is not pure/nothrow/@safe + static struct S + { + int x; + this(this) @system {} + bool opEquals(ref const S s) const @system { return s.x == x; } + } + + auto storage = S(5); + + NullableRef!S s; + assert(s.isNull); + s.bind(&storage); + assert(!s.isNull); + assert(s.x == 5); + s.nullify(); + assert(s.isNull); +} /** $(D BlackHole!Base) is a subclass of $(D Base) which automatically implements From ff106ce830535fdb7caf0004fd3ce0ca7467b17e Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Fri, 17 Feb 2012 02:41:52 +0200 Subject: [PATCH 16/33] etc.c.sqlite3: Annotate extern variables as such --- etc/c/sqlite3.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/c/sqlite3.d b/etc/c/sqlite3.d index 5ab143330db..99edd556a7a 100644 --- a/etc/c/sqlite3.d +++ b/etc/c/sqlite3.d @@ -47,7 +47,7 @@ enum SQLITE_SOURCE_ID = "2011-04-17 17:25:17 154ddbc17120be2915eb03edc52 /** ** CAPI3REF: Run-Time Library Version Numbers */ -immutable(char)* sqlite3_version; +extern immutable(char)* sqlite3_version; /// Ditt immutable(char)* sqlite3_libversion(); /// Ditto @@ -1037,7 +1037,7 @@ int sqlite3_sleep(int); /** ** CAPI3REF: Name Of The Folder Holding Temporary Files */ -char *sqlite3_temp_directory; +extern char *sqlite3_temp_directory; /** ** CAPI3REF: Test For Auto-Commit Mode From 1c50ab96593e5fb9c82db5cb8083bd65c45f6c7f Mon Sep 17 00:00:00 2001 From: Jimmy Cao Date: Sat, 18 Feb 2012 12:43:25 -0600 Subject: [PATCH 17/33] avoid 1 allocation (per suggestion from Andrei) --- std/net/curl.d | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/std/net/curl.d b/std/net/curl.d index b26df2d9149..12b101b07d8 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -3339,7 +3339,9 @@ struct Curl private string errorString(CurlCode code) { - return format("%s on handle %s", to!string(curl_easy_strerror(code)), handle); + auto msgZ = curl_easy_strerror(code); + // doing the following (instead of just using std.conv.to!string) avoids 1 allocation + return format("%s on handle %s", cast(string) msgZ[0 .. core.stdc.strlen(msgZ)], handle); } private void throwOnStopped(string message = null) From 8d02b47947db69e65b9b8462bff6055462193759 Mon Sep 17 00:00:00 2001 From: Jimmy Cao Date: Sat, 18 Feb 2012 12:49:52 -0600 Subject: [PATCH 18/33] core.stdc.*string*.strlen --- std/net/curl.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/net/curl.d b/std/net/curl.d index 12b101b07d8..e5ec52b582c 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -3341,7 +3341,7 @@ struct Curl { auto msgZ = curl_easy_strerror(code); // doing the following (instead of just using std.conv.to!string) avoids 1 allocation - return format("%s on handle %s", cast(string) msgZ[0 .. core.stdc.strlen(msgZ)], handle); + return format("%s on handle %s", cast(string) msgZ[0 .. core.stdc.string.strlen(msgZ)], handle); } private void throwOnStopped(string message = null) From f999f6ba0e86a9e6b54f9853ca48d830396aec8e Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Sat, 18 Feb 2012 21:00:11 +0200 Subject: [PATCH 19/33] std.file: Use stat instead of access to check file existence on POSIX The reason for this change is the quirky behavior of access for SUID programs: a file may not appear to "exist", despite that the program would be able to open it just fine. The behavior in question is described as follows in the access man page: > The check is done using the calling process's real UID and GID, rather > than the effective IDs as is done when actually attempting an operation > (e.g., open(2)) on the file. This allows set-user-ID programs to easily > determine the invoking user's authority. While various operating systems provide eaccess or euidaccess functions, these are not part of POSIX - so it's safer to use stat instead. --- std/file.d | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/std/file.d b/std/file.d index 67d916ee71a..be13ecd2396 100644 --- a/std/file.d +++ b/std/file.d @@ -1136,7 +1136,28 @@ unittest } else version(Posix) { - return access(toStringz(name), 0) == 0; + /* + The reason why we use stat (and not access) here is + the quirky behavior of access for SUID programs: if + we used access, a file may not appear to "exist", + despite that the program would be able to open it + just fine. The behavior in question is described as + follows in the access man page: + + > The check is done using the calling process's real + > UID and GID, rather than the effective IDs as is + > done when actually attempting an operation (e.g., + > open(2)) on the file. This allows set-user-ID + > programs to easily determine the invoking user's + > authority. + + While various operating systems provide eaccess or + euidaccess functions, these are not part of POSIX - + so it's safer to use stat instead. + */ + + struct_stat64 statbuf = void; + return stat64(toStringz(name), &statbuf) == 0; } } From d1938e5563e785f9db36c6e9cf7c37bb69305a3a Mon Sep 17 00:00:00 2001 From: dsimcha Date: Sat, 18 Feb 2012 16:07:16 -0500 Subject: [PATCH 20/33] Add all to std.algorithm and alias canFind to any for consistency with standard functional programming terminology. --- std/algorithm.d | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/std/algorithm.d b/std/algorithm.d index 0daa4b34e62..eb15f762dd9 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -7790,6 +7790,34 @@ if (is(typeof(find!pred(range)))) return !find!pred(range).empty; } +/** +Alias for canFind, for consistency with terminology typically used in +functional languages. +*/ +alias canFind any; + +/** +Returns $(D true) if and only if all values in $(D range) satisfy the +predicate $(D pred). Performs $(BIGOH r.length) evaluations of $(D pred). + +Examples: +--- +assert(all!"a & 1"([1, 3, 5, 7, 9])); +assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); +--- +*/ +bool all(alias pred, R)(R range) +if(isInputRange!R && is(typeof(unaryFun!pred(range.front)))) +{ + return find!(not!(unaryFun!pred))(range).empty; +} + +unittest +{ + assert(all!"a & 1"([1, 3, 5, 7, 9])); + assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); +} + unittest { debug(std_algorithm) scope(success) From 9214e9e764aadd08740ba923f6799f6807bb60fe Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Sun, 19 Feb 2012 19:14:38 +0200 Subject: [PATCH 21/33] std.base64: Fix invariants when decoding truncated strings We should never throw Errors on malformed data - especially since the module does not provide validation facilities. Base64 is widely used on the web, so encoded strings need to be treated like user input. The added unittests are purposefully vague. This is to allow changing the implementation within the spec (whether to throw, ignore or try parsing trailing bytes). --- std/base64.d | 58 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/std/base64.d b/std/base64.d index 7e3f6d0e4ac..1984b95a0a4 100644 --- a/std/base64.d +++ b/std/base64.d @@ -715,19 +715,30 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') */ @safe pure nothrow size_t decodeLength(in size_t sourceLength) - in { static if (Padding == NoPadding) - assert(sourceLength % 4 != 1, "Invalid no-padding Base64 format"); + return (sourceLength / 4) * 3 + (sourceLength % 4 < 2 ? 0 : sourceLength % 4 == 2 ? 1 : 2); else - assert(sourceLength % 4 == 0, "Invalid Base64 format"); + return (sourceLength / 4) * 3; } - body + + + // Used in decode contracts. Calculates the actual size the decoded + // result should have, taking into account trailing padding. + @safe + pure nothrow private size_t realDecodeLength(R)(R source) { - static if (Padding == NoPadding) - return (sourceLength / 4) * 3 + (sourceLength % 4 == 0 ? 0 : sourceLength % 4 == 2 ? 1 : 2); - else - return (sourceLength / 4) * 3; + auto expect = decodeLength(source.length); + static if (Padding != NoPadding) + { + if (source.length % 4 == 0) + { + expect -= source.length == 0 ? 0 : + source[$ - 2] == Padding ? 2 : + source[$ - 1] == Padding ? 1 : 0; + } + } + return expect; } @@ -756,9 +767,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') } out(result) { - immutable expect = decodeLength(source.length) - (source.length == 0 ? 0 : - source[$ - 2] == Padding ? 2 : - source[$ - 1] == Padding ? 1 : 0); + immutable expect = realDecodeLength(source); assert(result.length == expect, "The length of result is different from the expected length"); } body @@ -900,9 +909,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=') !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte)) out(result) { - immutable expect = decodeLength(source.length) - (source.length == 0 ? 0 : - source[$ - 2] == Padding ? 2 : - source[$ - 1] == Padding ? 1 : 0); + immutable expect = realDecodeLength(source); assert(result == expect, "The result of decode is different from the expected"); } body @@ -1374,7 +1381,7 @@ unittest { alias Base64Impl!('!', '=', Base64.NoPadding) Base64Re; - // Test vectors from RPC 4648 + // Test vectors from RFC 4648 ubyte[][string] tv = [ "" :cast(ubyte[])"", "f" :cast(ubyte[])"f", @@ -1420,10 +1427,20 @@ unittest assert(Base64.decode(Base64.encode(tv["fooba"])) == tv["fooba"]); assert(Base64.decode(Base64.encode(tv["foobar"])) == tv["foobar"]); - try { - Base64.decode("ab|c"); - assert(false); - } catch (Exception e) {} + assertThrown(Base64.decode("ab|c")); + + // Test decoding incomplete strings. RFC does not specify the correct + // behavior, but the code should never throw Errors on invalid input. + + // decodeLength is nothrow + assert(Base64.decodeLength(1) == 0); + assert(Base64.decodeLength(2) <= 1); + assert(Base64.decodeLength(3) <= 2); + + // may throw Exceptions, may not throw Errors + collectException(Base64.decode("Zg")); + collectException(Base64.decode("Zg=")); + collectException(Base64.decode("Zm8")); } { // No padding @@ -1460,6 +1477,9 @@ unittest assert(Base64Re.decode(Base64Re.encode(tv["foob"])) == tv["foob"]); assert(Base64Re.decode(Base64Re.encode(tv["fooba"])) == tv["fooba"]); assert(Base64Re.decode(Base64Re.encode(tv["foobar"])) == tv["foobar"]); + + // decodeLength is nothrow + assert(Base64.decodeLength(1) == 0); } { // with OutputRange From f7c6e665b7e8ba675eba8c3837f526dc7eeb18ee Mon Sep 17 00:00:00 2001 From: dsimcha Date: Sun, 19 Feb 2012 13:15:43 -0500 Subject: [PATCH 22/33] Fix unlisted bug in std.typecons.Scoped. writeln() has no place in production code in these cases and wasn't properly imported either. --- std/typecons.d | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 33355c80254..0c25f316607 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -2687,8 +2687,7 @@ private struct Scoped(T) @disable this(this) { - writeln("Illegal call to Scoped this(this)"); - assert(false); + assert(false, "Illegal call to Scoped this(this)"); } ~this() From 4c9d907fcd63f48d055e83f85557e90aa52f647f Mon Sep 17 00:00:00 2001 From: dsimcha Date: Sun, 19 Feb 2012 20:41:59 -0500 Subject: [PATCH 23/33] Optimize fft to take advantage of symmetry for pure real FFTs. --- std/numeric.d | 177 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 150 insertions(+), 27 deletions(-) diff --git a/std/numeric.d b/std/numeric.d index 316331e4395..5d1cf6d6965 100644 --- a/std/numeric.d +++ b/std/numeric.d @@ -2167,8 +2167,9 @@ private alias float lookup_t; /**A class for performing fast Fourier transforms of power of two sizes. * This class encapsulates a large amount of state that is reusable when - * performing multiple FFTs of the same size. This makes performing numerous - * FFTs of the same size faster than a free function API would allow. However, + * performing multiple FFTs of sizes smaller than or equal to that specified + * in the constructor. This results in substantial speedups when performing + * multiple FFTs with a known maximum size. However, * a free function API is provided for convenience if you need to perform a * one-off FFT. * @@ -2180,7 +2181,7 @@ private: immutable lookup_t[][] negSinLookup; void enforceSize(R)(R range) const { - enforce(range.length == size, text( + enforce(range.length <= size, text( "FFT size mismatch. Expected ", size, ", got ", range.length)); } @@ -2189,21 +2190,6 @@ private: assert(range.length >= 4); assert(isPowerOfTwo(range.length)); } body { - immutable localLookup = negSinLookup[bsf(range.length)]; - assert(localLookup.length == range.length); - - immutable cosMask = range.length - 1; - immutable cosAdd = range.length / 4 * 3; - - lookup_t negSinFromLookup(size_t index) pure nothrow { - return localLookup[index]; - } - - lookup_t cosFromLookup(size_t index) pure nothrow { - // cos is just -sin shifted by PI * 3 / 2. - return localLookup[(index + cosAdd) & cosMask]; - } - auto recurseRange = range; recurseRange.doubleSteps(); @@ -2218,8 +2204,127 @@ private: recurseRange.popHalf(); slowFourier2(recurseRange, buf[$ / 2..$]); } + + butterfly(buf); + } + + // 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 + // 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 + in { + assert(range.length >= 4); + assert(isPowerOfTwo(range.length)); + } body { + alias ElementType!R E; + + // Converts odd indices of range to the imaginary components of + // a range half the size. The even indices become the real components. + static if(isArray!R && isFloatingPoint!E) { + // Then the memory layout of complex numbers provides a dirt + // cheap way to convert. This is a common case, so take advantage. + auto oddsImag = cast(Complex!E[]) range; + } else { + // General case: Use a higher order range. We can assume + // source.length is even because it has to be a power of 2. + static struct OddToImaginary { + R source; + alias Complex!(CommonType!(E, typeof(buf[0].re))) C; + + @property { + C front() { + return C(source[0], source[1]); + } + + C back() { + immutable n = source.length; + return C(source[n - 2], source[n - 1]); + } + + typeof(this) save() { + return typeof(this)(source.save); + } + + bool empty() { + return source.empty; + } + + size_t length() { + return source.length / 2; + } + } + + void popFront() { + source.popFront(); + source.popFront(); + } + + void popBack() { + source.popBack(); + source.popBack(); + } + + C opIndex(size_t index) { + return C(source[index * 2], source[index * 2 + 1]); + } + + typeof(this) opSlice(size_t lower, size_t upper) { + return typeof(this)(source[lower * 2..upper * 2]); + } + } + + auto oddsImag = OddToImaginary(range); + } + + fft(oddsImag, buf[0..$ / 2]); + auto evenFft = buf[0..$ / 2]; + auto oddFft = buf[$ / 2..$]; + immutable halfN = evenFft.length; + oddFft[0].re = buf[0].im; + oddFft[0].im = 0; + evenFft[0].im = 0; + // evenFft[0].re is already right b/c it's aliased with buf[0].re. + + foreach(k; 1..halfN / 2 + 1) { + immutable bufk = buf[k]; + immutable bufnk = buf[buf.length / 2 - k]; + evenFft[k].re = 0.5 * (bufk.re + bufnk.re); + evenFft[halfN - k].re = evenFft[k].re; + evenFft[k].im = 0.5 * (bufk.im - bufnk.im); + evenFft[halfN - k].im = -evenFft[k].im; + + oddFft[k].re = 0.5 * (bufk.im + bufnk.im); + oddFft[halfN - k].re = oddFft[k].re; + oddFft[k].im = 0.5 * (bufnk.re - bufk.re); + oddFft[halfN - k].im = -oddFft[k].im; + } - immutable halfLen = range.length / 2; + butterfly(buf); + } + + void butterfly(R)(R buf) const + in { + assert(isPowerOfTwo(buf.length)); + } body { + immutable n = buf.length; + immutable localLookup = negSinLookup[bsf(n)]; + assert(localLookup.length == n); + + immutable cosMask = n - 1; + immutable cosAdd = n / 4 * 3; + + lookup_t negSinFromLookup(size_t index) pure nothrow { + return localLookup[index]; + } + + lookup_t cosFromLookup(size_t index) pure nothrow { + // cos is just -sin shifted by PI * 3 / 2. + return localLookup[(index + cosAdd) & cosMask]; + } + + immutable halfLen = n / 2; // This loop is unrolled and the two iterations are nterleaved relative // to the textbook FFT to increase ILP. This gives roughly 5% speedups @@ -2322,8 +2427,9 @@ private: } public: - /**Create an $(D Fft) object for computing fast Fourier transforms of the - * provided size. $(D size) must be a power of two. + /**Create an $(D Fft) object for computing fast Fourier transforms of + * power of two sizes of $(D size) or smaller. $(D size) must be a + * power of two. */ this(size_t size) { // Allocate all twiddle factor buffers in one contiguous block so that, @@ -2343,6 +2449,9 @@ public: * which will be interpreted as pure real values, or complex types with * properties or members $(D .re) and $(D .im) that can be read. * + * Note: Pure real FFTs are automatically detected and the relevant + * optimizations are performed. + * * Returns: An array of complex numbers representing the transformed data in * the frequency domain. */ @@ -2381,10 +2490,15 @@ public: slowFourier2(range, buf); return; } else { - static if(is(R : Stride!R)) { - return fftImpl(range, buf); - } else { - return fftImpl(Stride!R(range, 1), buf); + alias ElementType!R E; + static if(is(E : real)) { + return fftImplPureReal(range, buf); + } else { + static if(is(R : Stride!R)) { + return fftImpl(range, buf); + } else { + return fftImpl(Stride!R(range, 1), buf); + } } } } @@ -2476,15 +2590,24 @@ void inverseFft(Ret, R)(R range, Ret buf) { return fftObj.inverseFft!(Ret, R)(range, buf); } - unittest { - // Test values from R. + // Test values from R and Octave. auto arr = [1,2,3,4,5,6,7,8]; auto fft1 = fft(arr); assert(approxEqual(map!"a.re"(fft1), [36.0, -4, -4, -4, -4, -4, -4, -4])); assert(approxEqual(map!"a.im"(fft1), [0, 9.6568, 4, 1.6568, 0, -1.6568, -4, -9.6568])); + + auto fft1Retro = fft(retro(arr)); + assert(approxEqual(map!"a.re"(fft1Retro), + [36.0, 4, 4, 4, 4, 4, 4, 4])); + assert(approxEqual(map!"a.im"(fft1Retro), + [0, -9.6568, -4, -1.6568, 0, 1.6568, 4, 9.6568])); + + auto fft1Float = fft(to!(float[])(arr)); + assert(approxEqual(map!"a.re"(fft1), map!"a.re"(fft1Float))); + assert(approxEqual(map!"a.im"(fft1), map!"a.im"(fft1Float))); alias Complex!float C; auto arr2 = [C(1,2), C(3,4), C(5,6), C(7,8), C(9,10), From 3ba8e17d99a10a86f3896f2a784187e1d18f6346 Mon Sep 17 00:00:00 2001 From: Daniel Murphy Date: Mon, 20 Feb 2012 17:00:41 +1100 Subject: [PATCH 24/33] There is no two argument version of fstp. --- std/math.d | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/std/math.d b/std/math.d index 9709dbbe4c9..8579e729e09 100644 --- a/std/math.d +++ b/std/math.d @@ -1021,14 +1021,14 @@ L_largepositive: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [ESP+8+8], 0x7FFE; - fstp ST(0), ST; + fstp ST(0); fld real ptr [ESP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: add ESP,12+8; ret PARAMSIZE; L_largenegative: - fstp ST(0), ST; + fstp ST(0); fld1; fchs; // return -1. Underflow flag is not set. add ESP,12+8; @@ -1090,7 +1090,7 @@ L_largepositive: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [RSP+8+8], 0x7FFE; - fstp ST(0), ST; + fstp ST(0); fld real ptr [RSP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: @@ -1098,7 +1098,7 @@ L_was_nan: ret; L_largenegative: - fstp ST(0), ST; + fstp ST(0); fld1; fchs; // return -1. Underflow flag is not set. add RSP,24; @@ -1179,7 +1179,7 @@ L_subnormal: fld1; fscale; fstp real ptr [ESP+8]; // scratchreal = 2^^scratchint - fstp ST(0),ST; // drop scratchint + fstp ST(0); // drop scratchint jmp L_normal; L_extreme: // Extreme exponent. X is very large positive, very @@ -1198,7 +1198,7 @@ L_overflow: // squaring it will create infinity, and set overflow flag. mov word ptr [ESP+8+8], 0x7FFE; L_waslargenegative: - fstp ST(0), ST; + fstp ST(0); fld real ptr [ESP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: @@ -1279,7 +1279,7 @@ L_overflow: // squaring it will create infinity, and set overflow flag. mov word ptr [RSP+8+8], 0x7FFE; L_waslargenegative: - fstp ST(0), ST; + fstp ST(0); fld real ptr [RSP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: @@ -1756,7 +1756,7 @@ real scalbn(real x, int n) @trusted nothrow fild n; fld x; fscale; - fstp ST(1), ST; + fstp ST(1); } } else { return core.stdc.math.scalbnl(x, n); From bcd85585d6e97cff4042f8f7f206ee09fdb76922 Mon Sep 17 00:00:00 2001 From: Daniel Murphy Date: Mon, 20 Feb 2012 23:05:49 +1100 Subject: [PATCH 25/33] Missed one. --- std/math.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/math.d b/std/math.d index 8579e729e09..0831ddd447d 100644 --- a/std/math.d +++ b/std/math.d @@ -1260,7 +1260,7 @@ L_subnormal: fld1; fscale; fstp real ptr [RSP+8]; // scratchreal = 2^scratchint - fstp ST(0),ST; // drop scratchint + fstp ST(0); // drop scratchint jmp L_normal; L_extreme: // Extreme exponent. X is very large positive, very From 296de5833404971dd0a6c4737432d3f196705512 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Mon, 20 Feb 2012 17:05:12 +0400 Subject: [PATCH 26/33] `cast(string)` is neither necessary nor safe *`curl_easy_strerror` isn't documented as returning immutable string --- std/net/curl.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/net/curl.d b/std/net/curl.d index e5ec52b582c..60c2d376db9 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -3341,7 +3341,7 @@ struct Curl { auto msgZ = curl_easy_strerror(code); // doing the following (instead of just using std.conv.to!string) avoids 1 allocation - return format("%s on handle %s", cast(string) msgZ[0 .. core.stdc.string.strlen(msgZ)], handle); + return format("%s on handle %s", msgZ[0 .. core.stdc.string.strlen(msgZ)], handle); } private void throwOnStopped(string message = null) From 8a6bfd2529872fea1dea27a72b0327773301d064 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 20 Feb 2012 19:43:12 -0800 Subject: [PATCH 27/33] Revert "Merge pull request #120 from 9rnsr/rvalue-struct-literal" This reverts commit d780d9df0fe0bde8acc78b4b304af8cccf987531, reversing changes made to c6ae86ca4f975465a95ddc2e96ad17ed28464b13. --- std/bigint.d | 2 +- std/concurrency.d | 9 +++------ std/container.d | 12 ------------ std/datetime.d | 12 ------------ 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/std/bigint.d b/std/bigint.d index 6a24de3f363..71849cfa3f4 100644 --- a/std/bigint.d +++ b/std/bigint.d @@ -336,7 +336,7 @@ public: } /// - bool opEquals()(auto ref const BigInt y) const + bool opEquals(Tdummy=void)(ref const BigInt y) const { return sign == y.sign && y.data == data; } diff --git a/std/concurrency.d b/std/concurrency.d index f0c1c55df18..70581f14cb3 100644 --- a/std/concurrency.d +++ b/std/concurrency.d @@ -496,8 +496,7 @@ private void _send(T...)( Tid tid, T vals ) */ private void _send(T...)( MsgType type, Tid tid, T vals ) { - auto msg = Message( type, vals ); - tid.mbox.put( msg ); + tid.mbox.put( Message( type, vals ) ); } @@ -1043,8 +1042,7 @@ private if( *depends && tid != owner ) { auto e = new LinkTerminated( tid ); - auto msg = Message( MsgType.standard, e ); - if( onStandardMsg( msg ) ) + if( onStandardMsg( Message( MsgType.standard, e ) ) ) return true; throw e; } @@ -1053,8 +1051,7 @@ private { owner = Tid.init; auto e = new OwnerTerminated( tid ); - auto msg = Message( MsgType.standard, e ); - if( onStandardMsg( msg ) ) + if( onStandardMsg( Message( MsgType.standard, e ) ) ) return true; throw e; } diff --git a/std/container.d b/std/container.d index bcaabe54164..2b3fcfc03df 100644 --- a/std/container.d +++ b/std/container.d @@ -922,12 +922,6 @@ Comparison for equality. Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of elements in $(D rhs). */ - bool opEquals(const SList rhs) const - { - return opEquals(rhs); - } - - /// ditto bool opEquals(ref const SList rhs) const { const(Node) * n1 = _root, n2 = rhs._root; @@ -1640,12 +1634,6 @@ struct Array(T) if (!is(T : const(bool))) /** Comparison for equality. */ - bool opEquals(const Array rhs) const - { - return opEquals(rhs); - } - - /// ditto bool opEquals(ref const Array rhs) const { if (empty) return rhs.empty; diff --git a/std/datetime.d b/std/datetime.d index b6813742b91..9e5bb3dbd9c 100644 --- a/std/datetime.d +++ b/std/datetime.d @@ -799,12 +799,6 @@ public: Note that the time zone is ignored. Only the internal std times (which are in UTC) are compared. +/ - bool opEquals(const SysTime rhs) const pure nothrow - { - return opEquals(rhs); - } - - /// ditto bool opEquals(const ref SysTime rhs) const pure nothrow { return _stdTime == rhs._stdTime; @@ -30822,12 +30816,6 @@ public: /// - bool opEquals(const StopWatch rhs) const pure nothrow - { - return opEquals(rhs); - } - - /// ditto bool opEquals(const ref StopWatch rhs) const pure nothrow { return _timeStart == rhs._timeStart && From 2e919aa77ce9d5d346d64830cbbb79e9041e709f Mon Sep 17 00:00:00 2001 From: dsimcha Date: Mon, 20 Feb 2012 23:12:28 -0500 Subject: [PATCH 28/33] Schedule for deprecation the predicate-only version of canFind and make any handle that use case. --- std/algorithm.d | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/std/algorithm.d b/std/algorithm.d index eb15f762dd9..351501d108e 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -7777,24 +7777,35 @@ unittest } } -// canFind +/** +Forwards to $(D any) for backwards compatibility. + +$(RED Scheduled for deprecation in August 2012. Please use $(D any) instead.) +*/ +bool canFind(alias pred, Range)(Range range) +{ + return any!pred(range); +} + /** Returns $(D true) if and only if a value $(D v) satisfying the predicate $(D pred) can be found in the forward range $(D range). Performs $(BIGOH r.length) evaluations of $(D pred). */ - -bool canFind(alias pred, Range)(Range range) +bool any(alias pred, Range)(Range range) if (is(typeof(find!pred(range)))) { return !find!pred(range).empty; } -/** -Alias for canFind, for consistency with terminology typically used in -functional languages. -*/ -alias canFind any; +unittest +{ + debug(std_algorithm) scope(success) + writeln("unittest @", __FILE__, ":", __LINE__, " done."); + auto a = [ 1, 2, 0, 4 ]; + assert(canFind!"a == 2"(a)); + assert(any!"a == 2"(a)); +} /** Returns $(D true) if and only if all values in $(D range) satisfy the @@ -7818,14 +7829,6 @@ unittest assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); } -unittest -{ - debug(std_algorithm) scope(success) - writeln("unittest @", __FILE__, ":", __LINE__, " done."); - auto a = [ 1, 2, 0, 4 ]; - assert(canFind!"a == 2"(a)); -} - // Scheduled for deprecation. Use std.range.SortedRange.canFind. bool canFindSorted(alias pred = "a < b", Range, V)(Range range, V value) { pragma(msg, "std.algorithm.canFindSorted is scheduled for " ~ From 983349625feb6f6090ee07cbf6124b5d1c049992 Mon Sep 17 00:00:00 2001 From: Daniel Murphy Date: Tue, 21 Feb 2012 15:51:35 +1100 Subject: [PATCH 29/33] This only works because of a bug in dmd, and it was probably supposed to be a char literal. --- std/utf.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/utf.d b/std/utf.d index 434db0b4422..540d97e72e6 100644 --- a/std/utf.d +++ b/std/utf.d @@ -1388,7 +1388,7 @@ const(wchar)* toUTF16z(in char[] s) @trusted encode(r, c); } } - r ~= "\000"; + r ~= '\000'; return r.ptr; } From 8283af10c176bc1b6d676304ef085bf0fdb57ceb Mon Sep 17 00:00:00 2001 From: k-hara Date: Tue, 21 Feb 2012 20:25:10 +0900 Subject: [PATCH 30/33] Change opEquals signature to allow receiving rvalue. --- std/typecons.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index afc4bebbaae..752a7e655d5 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -1425,7 +1425,7 @@ unittest static struct S { int x; - bool opEquals(ref const S s) const @system { return s.x == x; } + bool opEquals(const S s) const @system { return s.x == x; } } Nullable!(S, S(711)) s; @@ -1571,7 +1571,7 @@ unittest { int x; this(this) @system {} - bool opEquals(ref const S s) const @system { return s.x == x; } + bool opEquals(const S s) const @system { return s.x == x; } } auto storage = S(5); From 66e13b2c276fbad1a7d7a0e90779e2322162a717 Mon Sep 17 00:00:00 2001 From: k-hara Date: Tue, 21 Feb 2012 21:03:01 +0900 Subject: [PATCH 31/33] Revert "Revert "Merge pull request #120 from 9rnsr/rvalue-struct-literal"" This reverts commit 8a6bfd2529872fea1dea27a72b0327773301d064. --- std/bigint.d | 2 +- std/concurrency.d | 9 ++++++--- std/container.d | 12 ++++++++++++ std/datetime.d | 12 ++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/std/bigint.d b/std/bigint.d index 71849cfa3f4..6a24de3f363 100644 --- a/std/bigint.d +++ b/std/bigint.d @@ -336,7 +336,7 @@ public: } /// - bool opEquals(Tdummy=void)(ref const BigInt y) const + bool opEquals()(auto ref const BigInt y) const { return sign == y.sign && y.data == data; } diff --git a/std/concurrency.d b/std/concurrency.d index 70581f14cb3..f0c1c55df18 100644 --- a/std/concurrency.d +++ b/std/concurrency.d @@ -496,7 +496,8 @@ private void _send(T...)( Tid tid, T vals ) */ private void _send(T...)( MsgType type, Tid tid, T vals ) { - tid.mbox.put( Message( type, vals ) ); + auto msg = Message( type, vals ); + tid.mbox.put( msg ); } @@ -1042,7 +1043,8 @@ private if( *depends && tid != owner ) { auto e = new LinkTerminated( tid ); - if( onStandardMsg( Message( MsgType.standard, e ) ) ) + auto msg = Message( MsgType.standard, e ); + if( onStandardMsg( msg ) ) return true; throw e; } @@ -1051,7 +1053,8 @@ private { owner = Tid.init; auto e = new OwnerTerminated( tid ); - if( onStandardMsg( Message( MsgType.standard, e ) ) ) + auto msg = Message( MsgType.standard, e ); + if( onStandardMsg( msg ) ) return true; throw e; } diff --git a/std/container.d b/std/container.d index 2b3fcfc03df..bcaabe54164 100644 --- a/std/container.d +++ b/std/container.d @@ -922,6 +922,12 @@ Comparison for equality. Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of elements in $(D rhs). */ + bool opEquals(const SList rhs) const + { + return opEquals(rhs); + } + + /// ditto bool opEquals(ref const SList rhs) const { const(Node) * n1 = _root, n2 = rhs._root; @@ -1634,6 +1640,12 @@ struct Array(T) if (!is(T : const(bool))) /** Comparison for equality. */ + bool opEquals(const Array rhs) const + { + return opEquals(rhs); + } + + /// ditto bool opEquals(ref const Array rhs) const { if (empty) return rhs.empty; diff --git a/std/datetime.d b/std/datetime.d index 9e5bb3dbd9c..b6813742b91 100644 --- a/std/datetime.d +++ b/std/datetime.d @@ -799,6 +799,12 @@ public: Note that the time zone is ignored. Only the internal std times (which are in UTC) are compared. +/ + bool opEquals(const SysTime rhs) const pure nothrow + { + return opEquals(rhs); + } + + /// ditto bool opEquals(const ref SysTime rhs) const pure nothrow { return _stdTime == rhs._stdTime; @@ -30816,6 +30822,12 @@ public: /// + bool opEquals(const StopWatch rhs) const pure nothrow + { + return opEquals(rhs); + } + + /// ditto bool opEquals(const ref StopWatch rhs) const pure nothrow { return _timeStart == rhs._timeStart && From f7e0387b6dd2b3c63e0c3ef4ee4e0c49810d93ec Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Wed, 22 Feb 2012 17:37:56 +0200 Subject: [PATCH 32/33] std.algorithm: Fix the documentation of remove with pred The description contradicted the example/unittest/actual behavior. --- std/algorithm.d | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/std/algorithm.d b/std/algorithm.d index 144d24f3c85..f2f027fc885 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -6078,18 +6078,17 @@ unittest } /** -Reduces the length of the bidirectional range $(D range) by only -keeping elements that satisfy $(D pred). If $(D s = -SwapStrategy.unstable), elements are moved from the right end of the -range over the elements to eliminate. If $(D s = SwapStrategy.stable) -(the default), elements are moved progressively to front such that -their relative order is preserved. Returns the tail portion of the -range that was moved. +Reduces the length of the bidirectional range $(D range) by removing +elements that satisfy $(D pred). If $(D s = SwapStrategy.unstable), +elements are moved from the right end of the range over the elements +to eliminate. If $(D s = SwapStrategy.stable) (the default), +elements are moved progressively to front such that their relative +order is preserved. Returns the filtered range. Example: ---- int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ]; -assert(a[0 .. remove!("a == 2")(a).length] == [ 1, 3, 3, 4, 5, 5, 6 ]); +assert(remove!("a == 2")(a) == [ 1, 3, 3, 4, 5, 5, 6 ]); ---- */ Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range) From 4b17d07b8e640ae342ce1d28199c32ed8aa19fa4 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Thu, 23 Feb 2012 01:42:23 -0700 Subject: [PATCH 33/33] Just an adorable little typo I noticed in std.regex's documentation. --- std/regex.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/regex.d b/std/regex.d index d1ab02b61bc..347595df8af 100644 --- a/std/regex.d +++ b/std/regex.d @@ -6763,7 +6763,7 @@ public: } } -///A helper function, creates a $(D Spliiter) on range $(D r) separated by regex $(D pat). +///A helper function, creates a $(D Splitter) on range $(D r) separated by regex $(D pat). public Splitter!(Range) splitter(Range, RegEx)(Range r, RegEx pat) if( is(BasicElementOf!Range : dchar) && is(RegEx == Regex!(BasicElementOf!Range))) {