mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 06:00:35 +03:00
merge r387:397 from candidate to trunk
-- new module std.contracts -- migrate callers to it where appropriate
This commit is contained in:
parent
9fa812d984
commit
a9bc53273c
27 changed files with 736 additions and 443 deletions
|
@ -71,7 +71,7 @@ INTERNAL_GC_EXTRAFILES = \
|
|||
internal/gc/win32.mak \
|
||||
internal/gc/linux.mak
|
||||
|
||||
STD_MODULES = array asserterror base64 bind bitarray boxer compiler \
|
||||
STD_MODULES = array asserterror base64 bind bitarray boxer compiler contracts \
|
||||
conv cover cpuid cstream ctype date dateparse demangle file format gc \
|
||||
getopt hiddenfunc intrinsic loader math math2 md5 metastrings mmfile \
|
||||
moduleinit openrj outbuffer outofmemory path perf process random \
|
||||
|
|
1
std.ddoc
1
std.ddoc
|
@ -116,6 +116,7 @@ NAVIGATION_PHOBOS=
|
|||
$(LI <a href="std_bitarray.html" title="Arrays of bits">std.bitarray</a>)
|
||||
$(LI <a href="std_boxer.html" title="Box/unbox types">std.boxer</a>)
|
||||
$(LI <a href="std_compiler.html" title="Information about the D compiler implementation">std.compiler</a>)
|
||||
$(LI <a href="std_contracts.html" title="Think assert">std.contracts</a>)
|
||||
$(LI <a href="std_conv.html" title="Conversion of strings to integers">std.conv</a>)
|
||||
$(LI <a href="std_cover.html" title="D coverage analyzer">std.cover</a>)
|
||||
$(LI <a href="std_cpuid.html" title="CPU identification">std.cpuid</a>)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module std.array;
|
||||
|
||||
private import std.c.stdio;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
class ArrayBoundsError : Error
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ module std.asserterror;
|
|||
|
||||
import std.c.stdio;
|
||||
import std.c.stdlib;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
class AssertError : Error
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ module std.boxer;
|
|||
private import std.format;
|
||||
private import std.string;
|
||||
private import std.utf;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
/* These functions and types allow packing objects into generic containers
|
||||
* and recovering them later. This comes into play in a wide spectrum of
|
||||
|
|
257
std/contracts.d
Normal file
257
std/contracts.d
Normal file
|
@ -0,0 +1,257 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* This module defines tools for effecting contracts and enforcing
|
||||
* predicates (a la $(D_PARAM assert)).
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdContracts
|
||||
*
|
||||
* Synopsis:
|
||||
*
|
||||
* ----
|
||||
* string synopsis()
|
||||
* {
|
||||
* FILE* f = enforce(fopen("some/file"));
|
||||
* // f is not null from here on
|
||||
* FILE* g = enforceEx!(WriteException)(fopen("some/other/file", "w"));
|
||||
* // g is not null from here on
|
||||
* Exception e = collectException(write(g, readln(f)));
|
||||
* if (e)
|
||||
* {
|
||||
* ... an exception occurred...
|
||||
* }
|
||||
* char[] line;
|
||||
* enforce(readln(f, line));
|
||||
* return assumeUnique(line);
|
||||
* }
|
||||
* ----
|
||||
*
|
||||
* Author:
|
||||
* Andrei Alexandrescu
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
* Brad Roberts came up with the name $(D_PARAM contracts).
|
||||
*/
|
||||
|
||||
module std.contracts;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Andrei Alexandrescu, www.erdani.org
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws
|
||||
* $(D_PARAM new Exception(msg)).
|
||||
* Example:
|
||||
* ----
|
||||
* auto f = enforce(fopen("data.txt"));
|
||||
* auto line = readln(f);
|
||||
* enforce(line.length); // expect a non-empty line
|
||||
* ----
|
||||
*/
|
||||
|
||||
T enforce(T)(T value, lazy string msg = "")
|
||||
{
|
||||
if (value) return value;
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws
|
||||
* $(D_PARAM new E(msg)).
|
||||
* Example:
|
||||
* ----
|
||||
* auto f = enforceEx!(FileMissingException)(fopen("data.txt"));
|
||||
* auto line = readln(f);
|
||||
* enforceEx!(DataCorruptionException)(line.length);
|
||||
* ----
|
||||
*/
|
||||
|
||||
template enforceEx(E)
|
||||
{
|
||||
T enforceEx(T)(T value, lazy string msg = "")
|
||||
{
|
||||
if (value) return value;
|
||||
throw new E(msg);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
enforce(true);
|
||||
enforce(true, "blah");
|
||||
typedef Exception MyException;
|
||||
try
|
||||
{
|
||||
enforceEx!(MyException)(false);
|
||||
assert(false);
|
||||
}
|
||||
catch (MyException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates $(D_PARAM expression). If evaluation throws an exception,
|
||||
* return that exception. Otherwise, deposit the resulting value in
|
||||
* $(D_PARAM target) and return $(D_PARAM null).
|
||||
* Example:
|
||||
* ----
|
||||
* int[] a = new int[3];
|
||||
* int b;
|
||||
* assert(collectException(a[4], b));
|
||||
* ----
|
||||
*/
|
||||
|
||||
Exception collectException(T)(lazy T expression, ref T target)
|
||||
{
|
||||
try
|
||||
{
|
||||
target = expression();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[] a = new int[3];
|
||||
int b;
|
||||
int foo() { throw new Exception("blah"); }
|
||||
assert(collectException(foo(), b));
|
||||
}
|
||||
|
||||
/** Evaluates $(D_PARAM expression). If evaluation throws an
|
||||
* exception, return that exception. Otherwise, return $(D_PARAM
|
||||
* null). $(D_PARAM T) can be $(D_PARAM void).
|
||||
*/
|
||||
|
||||
Exception collectException(T)(lazy T expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
expression();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int foo() { throw new Exception("blah"); }
|
||||
assert(collectException(foo()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a mutable array to an invariant array in an idiomatic
|
||||
* manner. Technically, $(D_PARAM assumeUnique) just inserts a cast,
|
||||
* but its name documents assumptions on the part of the
|
||||
* caller. $(D_PARAM assumeUnique(arr)) should only be called when
|
||||
* there are no more active mutable aliases to elements of $(D_PARAM
|
||||
* arr). To strenghten this assumption, $(D_PARAM assumeUnique(arr))
|
||||
* also clears $(D_PARAM arr) before returning. Essentially $(D_PARAM
|
||||
* assumeUnique(arr)) indicates commitment from the caller that there
|
||||
* is no more mutable access to any of $(D_PARAM arr)'s elements
|
||||
* (transitively), and that all future accesses will be done through
|
||||
* the invariant array returned by $(D_PARAM assumeUnique).
|
||||
*
|
||||
* Typically, $(D_PARAM assumeUnique) is used to return arrays from
|
||||
* functions that have allocated and built them.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ----
|
||||
* string letters()
|
||||
* {
|
||||
* char[] result = new char['z' - 'a' + 1];
|
||||
* foreach (i, ref e; result)
|
||||
* {
|
||||
* e = 'a' + i;
|
||||
* }
|
||||
* return assumeUnique(result);
|
||||
* }
|
||||
* ----
|
||||
*
|
||||
* The use in the example above is correct because $(D_PARAM result)
|
||||
* was private to $(D_PARAM letters) and is unaccessible in writing
|
||||
* after the function returns. The following example shows an
|
||||
* incorrect use of $(D_PARAM assumeUnique).
|
||||
*
|
||||
* Bad:
|
||||
*
|
||||
* ----
|
||||
* private char[] buffer;
|
||||
* string letters(char first, char last)
|
||||
* {
|
||||
* if (first >= last) return null; // fine
|
||||
* auto sneaky = buffer;
|
||||
* sneaky.length = last - first + 1;
|
||||
* foreach (i, ref e; sneaky)
|
||||
* {
|
||||
* e = 'a' + i;
|
||||
* }
|
||||
* return assumeUnique(sneaky); // BAD
|
||||
* }
|
||||
* ----
|
||||
*
|
||||
* The example above wreaks havoc on client code because it is
|
||||
* modifying arrays that callers considered immutable. To obtain an
|
||||
* invariant array from the writable array $(D_PARAM buffer), replace
|
||||
* the last line with:
|
||||
* ----
|
||||
* return to!(string)(sneaky); // not that sneaky anymore
|
||||
* ----
|
||||
*
|
||||
* The call will duplicate the array appropriately.
|
||||
*
|
||||
* Checking for uniqueness during compilation is possible in certain
|
||||
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in the
|
||||
* $(LINK2 http://archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf,ArchJava)
|
||||
* language), but complicates the language considerably. The downside
|
||||
* of $(D_PARAM assumeUnique)'s
|
||||
* convention-based usage is that at this time there is no formal
|
||||
* checking of the correctness of the assumption; on the upside, the
|
||||
* idiomatic use of $(D_PARAM assumeUnique) is simple and rare enough
|
||||
* to make it tolerable.
|
||||
*
|
||||
*/
|
||||
|
||||
invariant(T)[] assumeUnique(T)(ref T[] array)
|
||||
{
|
||||
auto result = cast(invariant(T)[]) array;
|
||||
array = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[] arr = new int[1];
|
||||
auto arr1 = assumeUnique(arr);
|
||||
assert(is(typeof(arr1) == invariant(int)[]) && arr == null);
|
||||
}
|
98
std/conv.d
98
std/conv.d
|
@ -52,7 +52,7 @@ class ConvError : Error
|
|||
{
|
||||
this(string s)
|
||||
{
|
||||
super(cast(string) ("conversion " ~ s));
|
||||
super("conversion " ~ s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ class ConvOverflowError : Error
|
|||
{
|
||||
this(string s)
|
||||
{
|
||||
super(cast(string) ("Error: overflow " ~ s));
|
||||
super("Error: overflow " ~ s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,94 +699,6 @@ private N parseIntegral(S, N)(ref S s)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a mutable array to an invariant array in an idiomatic
|
||||
* manner. Technically, $(D_PARAM assumeUnique) just inserts a cast,
|
||||
* but its name documents assumptions on the part of the
|
||||
* caller. $(D_PARAM assumeUnique(arr)) should only be called when
|
||||
* there are no more active mutable aliases to elements of $(D_PARAM
|
||||
* arr). To strenghten this assumption, $(D_PARAM assumeUnique(arr))
|
||||
* also clears $(D_PARAM arr) before returning. Essentially $(D_PARAM
|
||||
* assumeUnique(arr)) indicates commitment from the caller that there
|
||||
* is no more mutable access to any of $(D_PARAM arr)'s elements
|
||||
* (transitively), and that all future accesses will be done through
|
||||
* the invariant array returned by $(D_PARAM assumeUnique).
|
||||
*
|
||||
* Typically, $(D_PARAM assumeUnique) is used to return arrays from
|
||||
* functions that have allocated and built them.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ----
|
||||
* string letters()
|
||||
* {
|
||||
* char[] result = new char['z' - 'a' + 1];
|
||||
* foreach (i, ref e; result)
|
||||
* {
|
||||
* e = 'a' + i;
|
||||
* }
|
||||
* return assumeUnique(result);
|
||||
* }
|
||||
* ----
|
||||
*
|
||||
* The use in the example above is correct because $(D_PARAM result)
|
||||
* was private to $(D_PARAM letters) and is unaccessible in writing
|
||||
* after the function returns. The following example shows an
|
||||
* incorrect use of $(D_PARAM assumeUnique).
|
||||
*
|
||||
* Bad:
|
||||
*
|
||||
* ----
|
||||
* private char[] buffer;
|
||||
* string letters(char first, char last)
|
||||
* {
|
||||
* if (first >= last) return null; // fine
|
||||
* auto sneaky = buffer;
|
||||
* sneaky.length = last - first + 1;
|
||||
* foreach (i, ref e; sneaky)
|
||||
* {
|
||||
* e = 'a' + i;
|
||||
* }
|
||||
* return assumeUnique(sneaky); // BAD
|
||||
* }
|
||||
* ----
|
||||
*
|
||||
* The example above wreaks havoc on client code because it is
|
||||
* modifying arrays that callers considered immutable. To obtain an
|
||||
* invariant array from the writable array $(D_PARAM buffer), replace
|
||||
* the last line with:
|
||||
* ----
|
||||
* return to!(string)(sneaky); // not that sneaky anymore
|
||||
* ----
|
||||
*
|
||||
* The call will duplicate the array appropriately.
|
||||
*
|
||||
* Checking for uniqueness during compilation is possible in certain
|
||||
* cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in the
|
||||
* $(LINK2 http://archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf,ArchJava)
|
||||
* language), but complicates the language considerably. The downside
|
||||
* of $(D_PARAM assumeUnique)'s
|
||||
* convention-based usage is that at this time there is no formal
|
||||
* checking of the correctness of the assumption; on the upside, the
|
||||
* idiomatic use of $(D_PARAM assumeUnique) is simple and rare enough
|
||||
* to make it tolerable.
|
||||
*
|
||||
*/
|
||||
|
||||
invariant(T)[] assumeUnique(T)(ref T[] array)
|
||||
{
|
||||
auto result = cast(invariant(T)[]) array;
|
||||
array = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[] arr = new int[1];
|
||||
auto arr1 = assumeUnique(arr);
|
||||
assert(is(typeof(arr1) == invariant(int)[]) && arr == null);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Convert character string to the return type. These functions will be
|
||||
deprecated because $(D_PARAM to!(T)) supersedes them.
|
||||
|
@ -1422,7 +1334,7 @@ F parseFloating(S : S[], F)(ref S[] s)
|
|||
s = s[endptr - sz .. $];
|
||||
return f;
|
||||
Lerr:
|
||||
conv_error(cast(string) (s ~ " not representable as a " ~ F.stringof));
|
||||
conv_error(to!(string)(s) ~ " not representable as a " ~ F.stringof);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
@ -1978,8 +1890,8 @@ private bool getComplexStrings(string s, out string s1, out string s2)
|
|||
|
||||
Lerr:
|
||||
// Display the original string in the error message.
|
||||
conv_error(cast(string) ("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\""
|
||||
~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\""));
|
||||
conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\""
|
||||
~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\"");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ module std.date;
|
|||
|
||||
private import std.stdio;
|
||||
private import std.dateparse;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
/**
|
||||
* d_time is a signed arithmetic type giving the time elapsed since January 1,
|
||||
|
|
|
@ -38,7 +38,7 @@ class DateParseError : Error
|
|||
{
|
||||
this(string s)
|
||||
{
|
||||
super(cast(string) ("Invalid date string: " ~ s));
|
||||
super("Invalid date string: " ~ s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ module std.demangle;
|
|||
private import std.ctype;
|
||||
private import std.string;
|
||||
private import std.utf;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
private import std.stdio;
|
||||
|
||||
|
@ -204,24 +204,24 @@ string demangle(string name)
|
|||
case 'w': p = "dchar"; goto L1;
|
||||
|
||||
case 'A': // dynamic array
|
||||
p = cast(string) (parseType() ~ "[]");
|
||||
p = parseType() ~ "[]";
|
||||
goto L1;
|
||||
|
||||
case 'P': // pointer
|
||||
p = cast(string) (parseType() ~ "*");
|
||||
p = parseType() ~ "*";
|
||||
goto L1;
|
||||
|
||||
case 'G': // static array
|
||||
{ size_t ns = ni;
|
||||
parseNumber();
|
||||
size_t ne = ni;
|
||||
p = cast(string) (parseType() ~ "[" ~ name[ns .. ne] ~ "]");
|
||||
p = parseType() ~ "[" ~ name[ns .. ne] ~ "]";
|
||||
goto L1;
|
||||
}
|
||||
|
||||
case 'H': // associative array
|
||||
p = parseType();
|
||||
p = cast(string) (parseType() ~ "[" ~ p ~ "]");
|
||||
p = parseType() ~ "[" ~ p ~ "]";
|
||||
goto L1;
|
||||
|
||||
case 'D': // delegate
|
||||
|
@ -296,10 +296,9 @@ string demangle(string name)
|
|||
p ~= parseType() ~ " " ~ identifier ~ "(" ~ args ~ ")";
|
||||
return p;
|
||||
}
|
||||
p = cast(string) (parseType() ~
|
||||
p = parseType() ~
|
||||
(isdelegate ? " delegate(" : " function(") ~
|
||||
args ~
|
||||
")");
|
||||
args ~ ")";
|
||||
isdelegate = 0;
|
||||
goto L1;
|
||||
}
|
||||
|
|
|
@ -879,7 +879,7 @@ class FileException : Exception
|
|||
|
||||
this(string name, string message)
|
||||
{
|
||||
super(cast(string) (name ~ ": " ~ message));
|
||||
super(name ~ ": " ~ message);
|
||||
}
|
||||
|
||||
this(string name, uint errno)
|
||||
|
|
|
@ -81,9 +81,9 @@ class FormatError : Error
|
|||
super("std.format");
|
||||
}
|
||||
|
||||
this(const char[] msg)
|
||||
this(string msg)
|
||||
{
|
||||
super(cast(string) ("std.format " ~ msg));
|
||||
super("std.format " ~ msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2057,7 +2057,7 @@ void formattedWrite(Writer, F, A...)(ref Writer w, F[] fmt, A args)
|
|||
// leftover spec?
|
||||
if (fmt.length)
|
||||
{
|
||||
throw new FormatError("Orphan format specifier: %" ~ fmt);
|
||||
throw new FormatError(cast(string) ("Orphan format specifier: %" ~ fmt));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class HiddenFuncError : Error
|
|||
|
||||
this(ClassInfo ci)
|
||||
{
|
||||
super(cast(string) ("hidden method called for " ~ ci.name));
|
||||
super("hidden method called for " ~ ci.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class NotImplemented : Error
|
|||
{
|
||||
this(string msg)
|
||||
{
|
||||
super(cast(string) (msg ~ "not implemented"));
|
||||
super(msg ~ "not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,8 @@ module std.md5;
|
|||
|
||||
//debug=md5; // uncomment to turn on debugging printf's
|
||||
|
||||
import std.string, std.conv;
|
||||
import std.string;
|
||||
import std.contracts;
|
||||
|
||||
/***************************************
|
||||
* Computes MD5 digest of array of data.
|
||||
|
|
|
@ -718,7 +718,7 @@ private:
|
|||
}
|
||||
|
||||
// Always add on to the previous line
|
||||
nextLine = cast(string) (nextLine ~ line);
|
||||
nextLine = nextLine ~ line;
|
||||
|
||||
line = null;
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ string defaultExt(string filename, string ext)
|
|||
if (filename.length && filename[filename.length - 1] == '.')
|
||||
filename ~= ext;
|
||||
else
|
||||
filename = cast(string) (filename ~ "." ~ ext);
|
||||
filename = filename ~ "." ~ ext;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
@ -515,11 +515,11 @@ string addExt(string filename, string ext)
|
|||
if (filename.length && filename[filename.length - 1] == '.')
|
||||
filename ~= ext;
|
||||
else
|
||||
filename = cast(string) (filename ~ "." ~ ext);
|
||||
filename = filename ~ "." ~ ext;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = cast(string) (filename[0 .. $ - existing.length] ~ ext);
|
||||
filename = filename[0 .. $ - existing.length] ~ ext;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
@ -655,7 +655,7 @@ string join(string p1, string p2)
|
|||
}
|
||||
else if (p1[p1.length - 1] == sep[0])
|
||||
{
|
||||
p = cast(string) (p1 ~ p2);
|
||||
p = p1 ~ p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -142,9 +142,9 @@ int _spawnvp(int mode, char *pathname, char **argv)
|
|||
Lerror:
|
||||
retval = getErrno;
|
||||
throw new Exception(
|
||||
cast(string) ("Cannot spawn " ~ toString(pathname) ~ "; "
|
||||
"Cannot spawn " ~ toString(pathname) ~ "; "
|
||||
~ toString(strerror(retval))
|
||||
~ " [errno " ~ toString(retval) ~ "]"));
|
||||
~ " [errno " ~ toString(retval) ~ "]");
|
||||
} // _spawnvp
|
||||
private
|
||||
{
|
||||
|
|
|
@ -649,8 +649,7 @@ class InternetAddress: Address
|
|||
if(!ih.getHostByName(addr))
|
||||
//throw new AddressException("Invalid internet address");
|
||||
throw new AddressException(
|
||||
cast(string) ("Unable to resolve host '" ~ addr
|
||||
~ "'"));
|
||||
"Unable to resolve host '" ~ addr ~ "'");
|
||||
uiaddr = ih.addrList[0];
|
||||
}
|
||||
sin.sin_addr.s_addr = htonl(uiaddr);
|
||||
|
@ -690,7 +689,7 @@ class InternetAddress: Address
|
|||
/// Human readable string representing the IPv4 address and port in the form $(I a.b.c.d:e).
|
||||
string toString()
|
||||
{
|
||||
return cast(string) (toAddrString() ~ ":" ~ toPortString());
|
||||
return toAddrString() ~ ":" ~ toPortString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
25
std/stdio.d
25
std/stdio.d
|
@ -27,6 +27,7 @@ import std.c.string;
|
|||
import std.c.stddef;
|
||||
import std.conv;
|
||||
import std.traits;
|
||||
import std.contracts;
|
||||
import std.file, std.typetuple; // for testing only
|
||||
|
||||
version (DigitalMars)
|
||||
|
@ -1257,27 +1258,3 @@ unittest
|
|||
}
|
||||
fclose(f) == 0 || assert(false);
|
||||
}
|
||||
|
||||
T enforce(T)(T value, lazy string msg = "")
|
||||
{
|
||||
if (value) return value;
|
||||
throw new Exception(msg());
|
||||
}
|
||||
|
||||
template enforceEx(E)
|
||||
{
|
||||
T enforceEx(T)(T value, lazy string msg = "")
|
||||
{
|
||||
if (value) return value;
|
||||
throw new E(msg());
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
enforce(true);
|
||||
enforce(true, "blah");
|
||||
enforceEx!(StdioException)(true);
|
||||
// enforce!(Exception)(true, "blah");
|
||||
}
|
||||
|
||||
|
|
17
std/string.d
17
std/string.d
|
@ -39,7 +39,7 @@ private import std.array;
|
|||
private import std.format;
|
||||
private import std.ctype;
|
||||
private import std.stdarg;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
extern (C)
|
||||
{
|
||||
|
@ -2298,7 +2298,7 @@ string toString(uint u)
|
|||
ndigits = 0;
|
||||
if (u < 10)
|
||||
// Avoid storage allocation for simple stuff
|
||||
return cast(string) digits[u .. u + 1];
|
||||
return digits[u .. u + 1];
|
||||
else
|
||||
{
|
||||
while (u)
|
||||
|
@ -2585,8 +2585,7 @@ body
|
|||
uint i = buffer.length;
|
||||
|
||||
if (value < radix && value < hexdigits.length)
|
||||
return cast(string)
|
||||
hexdigits[cast(size_t)value .. cast(size_t)value + 1];
|
||||
return hexdigits[cast(size_t)value .. cast(size_t)value + 1];
|
||||
|
||||
do
|
||||
{ ubyte c;
|
||||
|
@ -2677,7 +2676,7 @@ string format(...)
|
|||
* enough to hold the result. Throws ArrayBoundsError if it is not.
|
||||
* Returns: s
|
||||
*/
|
||||
string sformat(char[] s, ...)
|
||||
char[] sformat(char[] s, ...)
|
||||
{ size_t i;
|
||||
|
||||
void putc(dchar c)
|
||||
|
@ -2700,7 +2699,7 @@ string sformat(char[] s, ...)
|
|||
}
|
||||
|
||||
std.format.doFormat(&putc, _arguments, _argptr);
|
||||
return cast(string) s[0 .. i];
|
||||
return s[0 .. i];
|
||||
}
|
||||
|
||||
|
||||
|
@ -3087,7 +3086,7 @@ string succ(string s)
|
|||
default:
|
||||
if (std.ctype.isalnum(c))
|
||||
r[i]++;
|
||||
return cast(string) r;
|
||||
return assumeUnique(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3562,14 +3561,14 @@ bool isNumeric(TypeInfo[] _arguments, va_list _argptr)
|
|||
{
|
||||
wchar[1] t;
|
||||
t[0] = va_arg!(wchar)(_argptr);
|
||||
return isNumeric(cast(string)std.utf.toUTF8(t));
|
||||
return isNumeric(std.utf.toUTF8(t));
|
||||
}
|
||||
else if (_arguments[0] == typeid(dchar))
|
||||
{
|
||||
dchar[1] t;
|
||||
t[0] = va_arg!(dchar)(_argptr);
|
||||
dchar[] t1 = t;
|
||||
return isNumeric(cast(string)std.utf.toUTF8(cast(dstring) t1));
|
||||
return isNumeric(std.utf.toUTF8(cast(dstring) t1));
|
||||
}
|
||||
//else if (_arguments[0] == typeid(cent))
|
||||
// return true;
|
||||
|
|
|
@ -580,7 +580,7 @@ class ThreadError : Error
|
|||
{
|
||||
this(string s)
|
||||
{
|
||||
super(cast(string) ("Thread error: " ~ s));
|
||||
super("Thread error: " ~ s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,24 +63,27 @@ template TypeTuple(TList...)
|
|||
* void foo()
|
||||
* {
|
||||
* writefln("The index of long is ",
|
||||
* IndexOf!(long, TypeTuple!(int, long, double)));
|
||||
* indexOf!(long, TypeTuple!(int, long, double)));
|
||||
* // prints: The index of long is 1
|
||||
* }
|
||||
* ---
|
||||
*/
|
||||
template IndexOf(T, TList...)
|
||||
template indexOf(T, TList...)
|
||||
{
|
||||
static if (TList.length == 0)
|
||||
const int IndexOf = -1;
|
||||
const int indexOf = -1;
|
||||
else static if (is(T == TList[0]))
|
||||
const int IndexOf = 0;
|
||||
const int indexOf = 0;
|
||||
else
|
||||
const int IndexOf =
|
||||
(IndexOf!(T, TList[1 .. length]) == -1)
|
||||
const int indexOf =
|
||||
(indexOf!(T, TList[1 .. length]) == -1)
|
||||
? -1
|
||||
: 1 + IndexOf!(T, TList[1 .. length]);
|
||||
: 1 + indexOf!(T, TList[1 .. length]);
|
||||
}
|
||||
|
||||
/// Kept for backwards compatibility
|
||||
alias indexOf IndexOf;
|
||||
|
||||
/**
|
||||
* Returns a typetuple created from TList with the first occurrence,
|
||||
* if any, of T removed.
|
||||
|
|
|
@ -48,7 +48,7 @@ private import std.ctype;
|
|||
private import std.c.stdlib;
|
||||
private import std.utf;
|
||||
private import std.stdio;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
class URIerror : Error
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
module std.utf;
|
||||
|
||||
private import std.stdio;
|
||||
import std.conv;
|
||||
import std.contracts;
|
||||
|
||||
//debug=utf; // uncomment to turn on debugging printf's
|
||||
|
||||
|
|
688
std/variant.d
688
std/variant.d
|
@ -13,31 +13,48 @@
|
|||
* Macros:
|
||||
* WIKI = Phobos/StdFormat
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
* Improvements to $(D_PARAM std.variant)'s code are due to Brad
|
||||
* Roberts.
|
||||
*
|
||||
* Synopsis:
|
||||
*
|
||||
* ----
|
||||
* Variant a; // must assign before use, otherwise exception ensues
|
||||
* Variant b = 42; // initialize with an integer; now the type is int
|
||||
* Variant a; // Must assign before use, otherwise exception ensues
|
||||
* // Initialize with an integer; make the type int
|
||||
* Variant b = 42;
|
||||
* assert(b.type == typeid(int));
|
||||
* assert(b.peek!(int) !is null && *b.peek!(int) == 42); // peek at the value
|
||||
* auto x = b.get!(real); // automatically convert to real
|
||||
* a = b; // assign Variants to one another
|
||||
* a = 3.14; // a is assigned a new value and also a new type (double)
|
||||
* // Peek at the value
|
||||
* assert(b.peek!(int) !is null && *b.peek!(int) == 42);
|
||||
* // Automatically convert per language rules
|
||||
* auto x = b.get!(real);
|
||||
* // Assign any other type, including other variants
|
||||
* a = b;
|
||||
* a = 3.14;
|
||||
* assert(a.type == typeid(double));
|
||||
* assert(a > b); // implicit conversions work just as with built-in types
|
||||
* // Implicit conversions work just as with built-in types
|
||||
* assert(a > b);
|
||||
* // Check for convertibility
|
||||
* assert(!a.convertsTo!(int)); // double not convertible to int
|
||||
* // Strings and all other arrays are supported
|
||||
* a = "now I'm a string";
|
||||
* assert(a == "now I'm a string");
|
||||
* assert(!a.convertsTo!(int)); // check for convertibility
|
||||
* a = new int[42]; // can also assign arrays
|
||||
* assert(a.length == 42);
|
||||
* a[5] = 7;
|
||||
* assert(a[5] == 7);
|
||||
* // Can also assign class values
|
||||
* class Foo {}
|
||||
* auto foo = new Foo;
|
||||
* a = foo; // can also assign class values
|
||||
* a = foo;
|
||||
* assert(*a.peek!(Foo) == foo); // and full type information is preserved
|
||||
* ----
|
||||
*
|
||||
* Author:
|
||||
* Andrei Alexandrescu
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
* Reviewed by Brad Roberts. Daniel Keep provided a detailed code
|
||||
* review prompting the following improvements: (1) better support for
|
||||
* arrays; (2) support for associative arrays; (3) friendlier behavior
|
||||
* towards the garbage collector.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -81,25 +98,29 @@ private template maxSize(T...)
|
|||
}
|
||||
|
||||
/**
|
||||
* $(D_PARAM VariantN) is a back-end type seldom used directly by user
|
||||
* code. Two commonly-used types using $(D_PARAM VariantN) as
|
||||
* back-end are:
|
||||
*
|
||||
* $(OL $(LI $(B Algebraic): A closed discriminated union with a
|
||||
* limited type universe (e.g., $(D_PARAM Algebraic!(int, double,
|
||||
* string)) only accepts these three types and rejects anything
|
||||
* else).) $(LI $(B Variant): An open discriminated union allowing an
|
||||
* unbounded set of types. The restriction is that the size of the
|
||||
* stored type cannot be larger than the largest built-in type. This
|
||||
* means that $(D_PARAM Variant) can accommodate all primitive types
|
||||
* and all user-defined types except for large $(D_PARAM struct)s.) )
|
||||
*
|
||||
* Both $(D_PARAM Algebraic) and $(D_PARAM Variant) share $(D_PARAM
|
||||
* VariantN)'s interface. (See their respective documentations below.)
|
||||
*
|
||||
* $(D_PARAM VariantN) is a discriminated union type parameterized
|
||||
* with the maximum size of the types stored $(D_PARAM maxDataSize),
|
||||
* and with the list of allowed types $(D_PARAM AllowedTypes). If the
|
||||
* list is empty, then any type up of size up to $(D_PARAM
|
||||
* with the largest size of the types stored ($(D_PARAM maxDataSize))
|
||||
* and with the list of allowed types ($(D_PARAM AllowedTypes)). If
|
||||
* the list is empty, then any type up of size up to $(D_PARAM
|
||||
* maxDataSize) (rounded up for alignment) can be stored in a
|
||||
* $(D_PARAM VariantN) object.
|
||||
*
|
||||
* $(D_PARAM VariantN) is a back-end type seldom used directly by user
|
||||
* code. Two commonly-used types using $(D_PARAM VariantN) as backend are:
|
||||
*
|
||||
* $(OL $(LI $(B Variant): A $(D_PARAM VariantN) allowing all types up
|
||||
* to the size of the largest built-in type. This means that they can
|
||||
* accommodate all primitive types and all user-defined types except
|
||||
* for large $(D_PARAM struct)s.) $(LI $(B Algebraic): A $(D_PARAM
|
||||
* VariantN) with a limited type universe, with
|
||||
* automatically-computed size (e.g., $(D_PARAM Algebraic!(int,
|
||||
* double, string)) only accepts these types and rejects anything
|
||||
* else).) )
|
||||
*
|
||||
*/
|
||||
|
||||
struct VariantN(size_t maxDataSize, AllowedTypes...)
|
||||
|
@ -113,42 +134,23 @@ private:
|
|||
}
|
||||
const size_t size = SizeChecker.sizeof - (int function()).sizeof;
|
||||
|
||||
// Tells whether a type T is allowed
|
||||
template allowed(T)
|
||||
/** Tells whether a type $(D_PARAM T) is statically allowed for
|
||||
* storage inside a $(D_PARAM VariantN) object by looking
|
||||
* $(D_PARAM T) up in $(D_PARAM AllowedTypes). If $(D_PARAM
|
||||
* AllowedTypes) is empty, all types of size up to $(D_PARAM
|
||||
* maxSize) are allowed.
|
||||
*/
|
||||
public template allowed(T)
|
||||
{
|
||||
static const bool allowed = !AllowedTypes.length
|
||||
|| IndexOf!(T, AllowedTypes) >= 0;
|
||||
static const bool allowed =
|
||||
(T.sizeof <= size || is(T == VariantN))
|
||||
&& (!AllowedTypes.length || indexOf!(T, AllowedTypes) >= 0);
|
||||
}
|
||||
|
||||
template StoredType(T, Candidates...)
|
||||
{
|
||||
static if (!AllowedTypes.length)
|
||||
{
|
||||
alias T Type; // anything allowed
|
||||
}
|
||||
else static if (!Candidates.length)
|
||||
{
|
||||
alias void Type; // not allowed
|
||||
}
|
||||
else
|
||||
{
|
||||
alias ImplicitConversionTargets!(T) Possible;
|
||||
static const IndexOf!(Candidates[0], Possible) cand;
|
||||
static if (cand >= 0)
|
||||
{
|
||||
alias Candidates[0] Type;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias StoredType!(T, Candidates[1 .. $]) Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Each internal operation is encoded with an identifier. See
|
||||
// the "handler" function below.
|
||||
enum OpID { getTypeInfo, get, compare, testConversion, toString,
|
||||
index, indexAssign, catAssign, copyOut }
|
||||
index, indexAssign, catAssign, copyOut, length }
|
||||
|
||||
// state
|
||||
int function(OpID selector, ubyte[size]* store, void* data) fptr
|
||||
|
@ -177,13 +179,9 @@ private:
|
|||
break;
|
||||
case OpID.compare:
|
||||
auto rhs = cast(VariantN *) parm;
|
||||
auto rhspA = rhs.peek!(A);
|
||||
if (!rhspA)
|
||||
{
|
||||
// types are different
|
||||
return int.min; // uninitialized variant is different from any
|
||||
}
|
||||
return 0; // all uninitialized are equal
|
||||
return rhs.peek!(A)
|
||||
? 0 // all uninitialized are equal
|
||||
: int.min; // uninitialized variant is not comparable otherwise
|
||||
break;
|
||||
case OpID.toString:
|
||||
string * target = cast(string*) parm;
|
||||
|
@ -194,6 +192,7 @@ private:
|
|||
case OpID.index:
|
||||
case OpID.indexAssign:
|
||||
case OpID.catAssign:
|
||||
case OpID.length:
|
||||
throw new VariantException(
|
||||
"Attempt to use an uninitialized VariantN");
|
||||
break;
|
||||
|
@ -205,19 +204,26 @@ private:
|
|||
// Handler for all of a type's operations
|
||||
static int handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
|
||||
{
|
||||
// Input: store points to a TypeInfo object
|
||||
// Output: store points to a copy of *me, if me was not null
|
||||
// Input: TypeInfo object
|
||||
// Output: target points to a copy of *me, if me was not null
|
||||
// Returns: true iff the A can be converted to the type represented
|
||||
// by the incoming TypeInfo
|
||||
static bool tryPutting(A* me, void* target)
|
||||
static bool tryPutting(A* me, TypeInfo targetType, void* target)
|
||||
{
|
||||
alias TypeTuple!(A, ImplicitConversionTargets!(A)) AllTypes;
|
||||
foreach (T ; AllTypes)
|
||||
{
|
||||
if (*cast(TypeInfo*) target != typeid(T)) continue;
|
||||
if (targetType != typeid(T)) continue;
|
||||
// found!!!
|
||||
static if (is(typeof(*cast(T*) target = *me)))
|
||||
{
|
||||
if (me) *cast(T*) target = *me;
|
||||
}
|
||||
else
|
||||
{
|
||||
// type is not assignable
|
||||
if (me) assert(false, typeof(A).stringof);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -230,46 +236,73 @@ private:
|
|||
break;
|
||||
case OpID.copyOut:
|
||||
auto target = cast(VariantN *) parm;
|
||||
memcpy(&target.store, pStore, target.store.sizeof);
|
||||
memcpy(&target.store, pStore, A.sizeof);
|
||||
target.fptr = &handler!(A);
|
||||
break;
|
||||
case OpID.get:
|
||||
return !tryPutting(cast(A*) pStore, parm);
|
||||
return !tryPutting(cast(A*) pStore, *cast(TypeInfo*) parm, parm);
|
||||
break; // for conformity
|
||||
case OpID.testConversion:
|
||||
return !tryPutting(null, parm);
|
||||
return !tryPutting(null, *cast(TypeInfo*) parm, null);
|
||||
break;
|
||||
case OpID.compare:
|
||||
auto rhs = cast(VariantN *) parm;
|
||||
A* rhspA = rhs.peek!(A);
|
||||
if (!rhspA)
|
||||
{
|
||||
// types are different
|
||||
// handling comparisons via conversions
|
||||
if (!rhs.convertsTo!(A))
|
||||
{
|
||||
return int.min; // dunno
|
||||
}
|
||||
auto rhsA = rhs.get!(A);
|
||||
rhspA = cast(typeof(rhspA)) &rhsA;
|
||||
}
|
||||
auto me = cast(A*) pStore;
|
||||
if (*rhspA == *me)
|
||||
auto rhsP = cast(VariantN *) parm;
|
||||
auto rhsType = rhsP.type;
|
||||
// Are we the same?
|
||||
if (rhsType == typeid(A))
|
||||
{
|
||||
return 0;
|
||||
// cool! Same type!
|
||||
auto rhsPA = cast(A*) &rhsP.store;
|
||||
if (*rhsPA == *me)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static if (is(typeof(A.init < A.init)))
|
||||
{
|
||||
return *me < *rhsPA ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// type doesn't support ordering comparisons
|
||||
return int.min;
|
||||
}
|
||||
}
|
||||
static if (is(typeof(A.init < A.init)))
|
||||
VariantN temp;
|
||||
// Do I convert to rhs?
|
||||
if (tryPutting(me, rhsType, &temp.store))
|
||||
{
|
||||
return *me < *rhspA ? -1 : 1;
|
||||
// cool, I do; temp's store contains my data in rhs's type!
|
||||
// also fix up its fptr
|
||||
temp.fptr = rhsP.fptr;
|
||||
// now lhsWithRhsType is a full-blown VariantN of rhs's type
|
||||
return temp.opCmp(*rhsP);
|
||||
}
|
||||
else
|
||||
// Does rhs convert to me?
|
||||
*cast(TypeInfo*) &temp.store = typeid(A);
|
||||
if (rhsP.fptr(OpID.get, &rhsP.store, &temp.store) == 0)
|
||||
{
|
||||
return int.min;
|
||||
// cool! Now temp has rhs in my type!
|
||||
auto rhsPA = cast(A*) temp.store;
|
||||
if (*rhsPA == *me)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static if (is(typeof(A.init < A.init)))
|
||||
{
|
||||
return *me < *rhsPA ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// type doesn't support ordering comparisons
|
||||
return int.min;
|
||||
}
|
||||
}
|
||||
return int.min; // dunno
|
||||
break;
|
||||
case OpID.toString:
|
||||
string * target = cast(string*) parm;
|
||||
A * me = cast(A*) pStore;
|
||||
auto target = cast(string*) parm;
|
||||
auto me = cast(A*) pStore;
|
||||
static if (is(typeof(to!(string)(*me))))
|
||||
{
|
||||
*target = to!(string)(*me);
|
||||
|
@ -322,7 +355,7 @@ private:
|
|||
break;
|
||||
case OpID.catAssign:
|
||||
auto me = cast(A*) pStore;
|
||||
static if (is(typeof((*me)[0])))
|
||||
static if (is(typeof((*me)[0])) && !is(typeof(me.keys)))
|
||||
{
|
||||
// array type; parm is the element to append
|
||||
auto arg = cast(VariantN*) parm;
|
||||
|
@ -343,6 +376,17 @@ private:
|
|||
throw new VariantException(typeid(A), typeid(void[]));
|
||||
}
|
||||
break;
|
||||
case OpID.length:
|
||||
auto me = cast(A*) pStore;
|
||||
static if (is(typeof(me.length)))
|
||||
{
|
||||
return me.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new VariantException(typeid(A), typeid(void[]));
|
||||
}
|
||||
break;
|
||||
default: assert(false);
|
||||
}
|
||||
return 0;
|
||||
|
@ -362,10 +406,8 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a $(D_PARAM VariantN) from a generic
|
||||
* argument. Statically rejects disallowed types.
|
||||
*/
|
||||
/** Assigns a $(D_PARAM VariantN) from a generic
|
||||
* argument. Statically rejects disallowed types. */
|
||||
|
||||
VariantN opAssign(T)(T rhs)
|
||||
{
|
||||
|
@ -396,8 +438,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if and only if the $(D_PARAM VariantN) object
|
||||
/** Returns true if and only if the $(D_PARAM VariantN) object
|
||||
* holds a valid value (has been initialized with, or assigned
|
||||
* from, a valid value).
|
||||
* Example:
|
||||
|
@ -416,11 +457,14 @@ public:
|
|||
{
|
||||
return fptr != &handler!(void);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the $(D_PARAM VariantN) object holds a value of the $(I
|
||||
* exact) type $(D_PARAM T), returns a pointer to that
|
||||
* value. Otherwise, returns $(D_PARAM null).
|
||||
* If the $(D_PARAM VariantN) object holds a value of the
|
||||
* $(I exact) type $(D_PARAM T), returns a pointer to that
|
||||
* value. Otherwise, returns $(D_PARAM null). In cases
|
||||
* where $(D_PARAM T) is statically disallowed, $(D_PARAM
|
||||
* peek) will not compile.
|
||||
*
|
||||
* Example:
|
||||
* ----
|
||||
* Variant a = 5;
|
||||
|
@ -430,7 +474,6 @@ public:
|
|||
* assert(a == 6);
|
||||
* ----
|
||||
*/
|
||||
|
||||
T * peek(T)()
|
||||
{
|
||||
static assert(allowed!(T), "Cannot store a " ~ T.stringof
|
||||
|
@ -439,7 +482,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the $(D_PARAM typeid) of the currently held object.
|
||||
* Returns the $(D_PARAM typeid) of the currently held value.
|
||||
*/
|
||||
|
||||
TypeInfo type()
|
||||
|
@ -462,7 +505,7 @@ public:
|
|||
return fptr(OpID.testConversion, null, &info) == 0;
|
||||
}
|
||||
|
||||
T[] testing123(T)(T*);
|
||||
private T[] testing123(T)(T*);
|
||||
|
||||
/**
|
||||
* A workaround for the fact that functions cannot return
|
||||
|
@ -557,23 +600,10 @@ public:
|
|||
int opEquals(T)(T rhs)
|
||||
{
|
||||
static if (is(T == VariantN))
|
||||
{
|
||||
return fptr(OpID.compare, &store, &rhs) == 0
|
||||
|| rhs.fptr(OpID.compare, &rhs.store, this) == 0;
|
||||
}
|
||||
alias rhs temp;
|
||||
else
|
||||
{
|
||||
if (convertsTo!(T))
|
||||
{
|
||||
return get!(T) == rhs;
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert rhs to my type instead
|
||||
auto temp = Variant(rhs);
|
||||
return fptr(OpID.compare, &store, &temp) == 0;
|
||||
}
|
||||
}
|
||||
auto temp = Variant(rhs);
|
||||
return fptr(OpID.compare, &store, &temp) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -585,24 +615,15 @@ public:
|
|||
int opCmp(T)(T rhs)
|
||||
{
|
||||
static if (is(T == VariantN))
|
||||
{
|
||||
auto result = fptr(OpID.compare, &store, &rhs);
|
||||
if (result == int.min)
|
||||
{
|
||||
result = -rhs.fptr(OpID.compare, &rhs.store, this);
|
||||
// hacky (shrewd?!) usage of the fact that -int.min == int.min
|
||||
if (result == int.min)
|
||||
{
|
||||
throw new VariantException(type, rhs.type);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
alias rhs temp;
|
||||
else
|
||||
auto temp = Variant(rhs);
|
||||
auto result = fptr(OpID.compare, &store, &temp);
|
||||
if (result == int.min)
|
||||
{
|
||||
auto lhs = get!(T);
|
||||
return lhs < rhs ? -1 : lhs == rhs ? 0 : 1;
|
||||
throw new VariantException(type, rhs.type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -614,106 +635,196 @@ public:
|
|||
return type.getHash(&store);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic between $(D_PARAM VariantN) objects and numeric values.
|
||||
*/
|
||||
|
||||
// arithmetic
|
||||
typeof(T+T) opAdd(T)( T rhs ) { return get!(T) + rhs; }
|
||||
///ditto
|
||||
typeof(T+T) opAdd_r(T)( T lhs ) { return lhs + get!(T); }
|
||||
///ditto
|
||||
typeof(T-T) opSub(T)( T rhs ) { return get!(T) - rhs; }
|
||||
///ditto
|
||||
typeof(T-T) opSub_r(T)( T lhs ) { return lhs - get!(T); }
|
||||
///ditto
|
||||
typeof(T*T) opMul(T)( T rhs ) { return get!(T) * rhs; }
|
||||
///ditto
|
||||
typeof(T*T) opMul_r(T)( T lhs ) { return lhs * get!(T); }
|
||||
///ditto
|
||||
typeof(T/T) opDiv(T)( T rhs ) { return get!(T) / rhs; }
|
||||
///ditto
|
||||
typeof(T/T) opDiv_r(T)( T lhs ) { return lhs / get!(T); }
|
||||
///ditto
|
||||
typeof(T%T) opMod(T)( T rhs ) { return get!(T) % rhs; }
|
||||
///ditto
|
||||
typeof(T%T) opMod_r(T)( T lhs ) { return lhs % get!(T); }
|
||||
///ditto
|
||||
typeof(T&T) opAnd(T)( T rhs ) { return get!(T) & rhs; }
|
||||
///ditto
|
||||
typeof(T&T) opAnd_r(T)( T lhs ) { return lhs & get!(T); }
|
||||
///ditto
|
||||
typeof(T|T) opOr(T)( T rhs ) { return get!(T) | rhs; }
|
||||
///ditto
|
||||
typeof(T|T) opOr_r(T)( T lhs ) { return lhs | get!(T); }
|
||||
///ditto
|
||||
typeof(T^T) opXor(T)( T rhs ) { return get!(T) ^ rhs; }
|
||||
///ditto
|
||||
typeof(T^T) opXor_r(T)( T lhs ) { return lhs ^ get!(T); }
|
||||
///ditto
|
||||
typeof(T<<T) opShl(T)( T rhs ) { return get!(T) << rhs; }
|
||||
///ditto
|
||||
typeof(T<<T) opShl_r(T)( T lhs ) { return lhs << get!(T); }
|
||||
///ditto
|
||||
typeof(T>>T) opShr(T)( T rhs ) { return get!(T) >> rhs; }
|
||||
///ditto
|
||||
typeof(T>>T) opShr_r(T)( T lhs ) { return lhs >> get!(T); }
|
||||
///ditto
|
||||
typeof(T>>>T) opUShr(T)( T rhs ) { return get!(T) >>> rhs; }
|
||||
///ditto
|
||||
typeof(T>>>T) opUShr_r(T)( T lhs ) { return lhs >>> get!(T); }
|
||||
///ditto
|
||||
typeof(T~T) opCat(T)( T rhs ) { return get!(typeof(T~T)) ~ rhs; }
|
||||
///ditto
|
||||
typeof(T~T) opCat_r(T)( T lhs ) { return lhs ~ get!(typeof(T~T)); }
|
||||
|
||||
///ditto
|
||||
VariantN opAddAssign(T)( T value ) { return *this = get!(T) + value; }
|
||||
///ditto
|
||||
VariantN opSubAssign(T)( T value ) { return *this = get!(T) - value; }
|
||||
///ditto
|
||||
VariantN opMulAssign(T)( T value ) { return *this = get!(T) * value; }
|
||||
///ditto
|
||||
VariantN opDivAssign(T)( T value ) { return *this = get!(T) / value; }
|
||||
///ditto
|
||||
VariantN opModAssign(T)( T value ) { return *this = get!(T) % value; }
|
||||
///ditto
|
||||
VariantN opAndAssign(T)( T value ) { return *this = get!(T) & value; }
|
||||
///ditto
|
||||
VariantN opOrAssign(T)( T value ) { return *this = get!(T) | value; }
|
||||
///ditto
|
||||
VariantN opXorAssign(T)( T value ) { return *this = get!(T) ^ value; }
|
||||
///ditto
|
||||
VariantN opShlAssign(T)( T value ) { return *this = get!(T) << value; }
|
||||
///ditto
|
||||
VariantN opShrAssign(T)( T value ) { return *this = get!(T) >> value; }
|
||||
///ditto
|
||||
VariantN opUShrAssign(T)( T value ) { return *this = get!(T) >>> value; }
|
||||
///ditto
|
||||
VariantN opCatAssign(T)( T value )
|
||||
private VariantN opArithmetic(T, string op)(T other)
|
||||
{
|
||||
auto toAppend = Variant(value);
|
||||
fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
|
||||
return *this;
|
||||
//return *this = get!(typeof(T~T)) ~ value;
|
||||
VariantN result;
|
||||
static if (is(T == VariantN))
|
||||
{
|
||||
if (convertsTo!(uint) && other.convertsTo!(uint))
|
||||
result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
|
||||
else if (convertsTo!(int) && other.convertsTo!(int))
|
||||
result = mixin("get!(int) " ~ op ~ " other.get!(int)");
|
||||
if (convertsTo!(ulong) && other.convertsTo!(ulong))
|
||||
result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
|
||||
else if (convertsTo!(long) && other.convertsTo!(long))
|
||||
result = mixin("get!(long) " ~ op ~ " other.get!(long)");
|
||||
else if (convertsTo!(double) && other.convertsTo!(double))
|
||||
result = mixin("get!(double) " ~ op ~ " other.get!(double)");
|
||||
else
|
||||
result = mixin("get!(real) " ~ op ~ " other.get!(real)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
|
||||
result = mixin("get!(uint) " ~ op ~ " other");
|
||||
else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
|
||||
result = mixin("get!(int) " ~ op ~ " other");
|
||||
if (is(typeof(T.max) : ulong) && T.min == 0 && convertsTo!(ulong))
|
||||
result = mixin("get!(ulong) " ~ op ~ " other");
|
||||
else if (is(typeof(T.max) : long) && T.min < 0 && convertsTo!(long))
|
||||
result = mixin("get!(long) " ~ op ~ " other");
|
||||
else if (is(T : double) && convertsTo!(double))
|
||||
result = mixin("get!(double) " ~ op ~ " other");
|
||||
else
|
||||
result = mixin("get!(real) " ~ op ~ " other");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private VariantN opLogic(T, string op)(T other)
|
||||
{
|
||||
VariantN result;
|
||||
static if (is(T == VariantN))
|
||||
{
|
||||
if (convertsTo!(uint) && other.convertsTo!(uint))
|
||||
result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
|
||||
else if (convertsTo!(int) && other.convertsTo!(int))
|
||||
result = mixin("get!(int) " ~ op ~ " other.get!(int)");
|
||||
if (convertsTo!(ulong) && other.convertsTo!(ulong))
|
||||
result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
|
||||
else
|
||||
result = mixin("get!(long) " ~ op ~ " other.get!(long)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
|
||||
result = mixin("get!(uint) " ~ op ~ " other");
|
||||
else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
|
||||
result = mixin("get!(int) " ~ op ~ " other");
|
||||
if (is(typeof(T.max) : ulong) && T.min == 0 && convertsTo!(ulong))
|
||||
result = mixin("get!(ulong) " ~ op ~ " other");
|
||||
else
|
||||
result = mixin("get!(long) " ~ op ~ " other");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array operations. If a $(D_PARAM VariantN) contains an array,
|
||||
* that array can be indexed into.
|
||||
* Arithmetic between $(D_PARAM VariantN) objects and numeric
|
||||
* values. All arithmetic operations return a $(D_PARAM VariantN)
|
||||
* object typed depending on the types of both values
|
||||
* involved. The conversion rules mimic D's built-in rules for
|
||||
* arithmetic conversions.
|
||||
*/
|
||||
|
||||
// Adapted from http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/Variant
|
||||
// arithmetic
|
||||
VariantN opAdd(T)(T rhs) { return opArithmetic!(T, "+")(rhs); }
|
||||
///ditto
|
||||
VariantN opSub(T)(T rhs) { return opArithmetic!(T, "-")(rhs); }
|
||||
///ditto
|
||||
VariantN opSub_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opArithmetic!(VariantN, "-")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opMul(T)(T rhs) { return opArithmetic!(T, "*")(rhs); }
|
||||
///ditto
|
||||
VariantN opDiv(T)(T rhs) { return opArithmetic!(T, "/")(rhs); }
|
||||
///ditto
|
||||
VariantN opDiv_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opArithmetic!(VariantN, "/")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opMod(T)(T rhs) { return opArithmetic!(T, "%")(rhs); }
|
||||
///ditto
|
||||
VariantN opMod_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opArithmetic!(VariantN, "%")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opAnd(T)(T rhs) { return opLogic!(T, "&")(rhs); }
|
||||
///ditto
|
||||
VariantN opOr(T)(T rhs) { return opLogic!(T, "|")(rhs); }
|
||||
///ditto
|
||||
VariantN opXor(T)(T rhs) { return opLogic!(T, "^")(rhs); }
|
||||
///ditto
|
||||
VariantN opShl(T)(T rhs) { return opLogic!(T, "<<")(rhs); }
|
||||
///ditto
|
||||
VariantN opShl_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opLogic!(VariantN, "<<")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opShr(T)(T rhs) { return opLogic!(T, ">>")(rhs); }
|
||||
///ditto
|
||||
VariantN opShr_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opLogic!(VariantN, ">>")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opUShr(T)(T rhs) { return opLogic!(T, ">>>")(rhs); }
|
||||
///ditto
|
||||
VariantN opUShr_r(T)(T lhs)
|
||||
{
|
||||
return VariantN(lhs).opLogic!(VariantN, ">>>")(*this);
|
||||
}
|
||||
///ditto
|
||||
VariantN opCat(T)(T rhs)
|
||||
{
|
||||
auto temp = *this;
|
||||
temp ~= rhs;
|
||||
return temp;
|
||||
}
|
||||
///ditto
|
||||
VariantN opCat_r(T)(T rhs)
|
||||
{
|
||||
VariantN temp = rhs;
|
||||
temp ~= *this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
///ditto
|
||||
VariantN opAddAssign(T)(T rhs) { return *this = *this + rhs; }
|
||||
///ditto
|
||||
VariantN opSubAssign(T)(T rhs) { return *this = *this - rhs; }
|
||||
///ditto
|
||||
VariantN opMulAssign(T)(T rhs) { return *this = *this * rhs; }
|
||||
///ditto
|
||||
VariantN opDivAssign(T)(T rhs) { return *this = *this / rhs; }
|
||||
///ditto
|
||||
VariantN opModAssign(T)(T rhs) { return *this = *this % rhs; }
|
||||
///ditto
|
||||
VariantN opAndAssign(T)(T rhs) { return *this = *this & rhs; }
|
||||
///ditto
|
||||
VariantN opOrAssign(T)(T rhs) { return *this = *this | rhs; }
|
||||
///ditto
|
||||
VariantN opXorAssign(T)(T rhs) { return *this = *this ^ rhs; }
|
||||
///ditto
|
||||
VariantN opShlAssign(T)(T rhs) { return *this = *this << rhs; }
|
||||
///ditto
|
||||
VariantN opShrAssign(T)(T rhs) { return *this = *this >> rhs; }
|
||||
///ditto
|
||||
VariantN opUShrAssign(T)(T rhs) { return *this = *this >>> rhs; }
|
||||
///ditto
|
||||
VariantN opCatAssign(T)(T rhs)
|
||||
{
|
||||
auto toAppend = VariantN(rhs);
|
||||
fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array and associative array operations. If a $(D_PARAM
|
||||
* VariantN) contains an (associative) array, it can be indexed
|
||||
* into. Otherwise, an exception is thrown.
|
||||
*
|
||||
* Example:
|
||||
* ----
|
||||
* auto a = Variant(new int[10]);
|
||||
* a[5] = 42;
|
||||
* assert(a[5] == 42);
|
||||
* int[int] hash = [ 42:24 ];
|
||||
* a = hash;
|
||||
* assert(a[42] == 24);
|
||||
* ----
|
||||
*
|
||||
* Caveat:
|
||||
*
|
||||
* Due to limitations in current language, read-modify-write
|
||||
* operations will not work properly:
|
||||
*
|
||||
* operations $(D_PARAM op=) will not work properly:
|
||||
*
|
||||
* ----
|
||||
* Variant a = new int[10];
|
||||
* a[5] = 42;
|
||||
|
@ -728,6 +839,15 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[int] hash = [ 42:24 ];
|
||||
Variant v = hash;
|
||||
assert(v[42] == 24);
|
||||
v[42] = 5;
|
||||
assert(v[42] == 5);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
VariantN opIndexAssign(T, N)(T value, N i)
|
||||
{
|
||||
|
@ -735,6 +855,49 @@ public:
|
|||
fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
/** If the $(D_PARAM VariantN) contains an (associative) array,
|
||||
* returns the length of that array. Otherwise, throws an
|
||||
* exception.
|
||||
*/
|
||||
size_t length()
|
||||
{
|
||||
return cast(size_t) fptr(OpID.length, &store, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Algebraic data type restricted to a closed set of possible
|
||||
* types. It's an alias for a $(D_PARAM VariantN) with an
|
||||
* appropriately-constructed maximum size. $(D_PARAM Algebraic) is
|
||||
* useful when it is desirable to restrict what a discriminated type
|
||||
* could hold to the end of defining simpler and more efficient
|
||||
* manipulation.
|
||||
*
|
||||
* Future additions to $(D_PARAM Algebraic) will allow compile-time
|
||||
* checking that all possible types are handled by user code,
|
||||
* eliminating a large class of errors.
|
||||
*
|
||||
* Bugs:
|
||||
*
|
||||
* Currently, $(D_PARAM Algebraic) does not allow recursive data
|
||||
* types. They will be allowed in a future iteration of the
|
||||
* implementation.
|
||||
*
|
||||
* Example:
|
||||
* ----
|
||||
* auto v = Algebraic!(int, double, string)(5);
|
||||
* assert(v.peek!(int));
|
||||
* v = 3.14;
|
||||
* assert(v.peek!(double));
|
||||
* // auto x = v.peek!(long); // won't compile, type long not allowed
|
||||
* // v = '1'; // won't compile, type char not allowed
|
||||
* ----
|
||||
*/
|
||||
|
||||
template Algebraic(T...)
|
||||
{
|
||||
alias VariantN!(maxSize!(T), T) Algebraic;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -749,6 +912,27 @@ public:
|
|||
|
||||
alias VariantN!(maxSize!(creal, char[], void delegate())) Variant;
|
||||
|
||||
/**
|
||||
* Returns an array of variants constructed from $(D_PARAM args).
|
||||
* Example:
|
||||
* ----
|
||||
* auto a = variantArray(1, 3.14, "Hi!");
|
||||
* assert(a[1] == 3.14);
|
||||
* auto b = Variant(a); // variant array as variant
|
||||
* assert(b[1] == 3.14);
|
||||
* ----
|
||||
*/
|
||||
|
||||
Variant[] variantArray(T...)(T args)
|
||||
{
|
||||
Variant[] result;
|
||||
foreach (arg; args)
|
||||
{
|
||||
result ~= Variant(arg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown in three cases:
|
||||
*
|
||||
|
@ -773,35 +957,14 @@ static class VariantException : Exception
|
|||
}
|
||||
this(TypeInfo source, TypeInfo target)
|
||||
{
|
||||
super(cast(string) ("Variant: attempting to use incompatible types "
|
||||
super("Variant: attempting to use incompatible types "
|
||||
~ source.toString
|
||||
~ " and " ~ target.toString));
|
||||
~ " and " ~ target.toString);
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of variants constructed from $(D_PARAM args).
|
||||
* Example:
|
||||
* ----
|
||||
* auto a = variantArray(1, 3.14, "Hi!");
|
||||
* assert(a[1] == 3.14);
|
||||
* auto b = Variant(a); // variant array as variant
|
||||
* assert(b[1] == 3.14);
|
||||
* ----
|
||||
*/
|
||||
|
||||
Variant[] variantArray(T...)(T args)
|
||||
{
|
||||
Variant[] result;
|
||||
foreach (arg; args)
|
||||
{
|
||||
result ~= Variant(arg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
// try it with an oddly small size
|
||||
|
@ -810,8 +973,10 @@ unittest
|
|||
|
||||
// variantArray tests
|
||||
auto heterogeneous = variantArray(1, 4.5, "hi");
|
||||
assert(heterogeneous.length == 3);
|
||||
auto variantArrayAsVariant = Variant(heterogeneous);
|
||||
assert(variantArrayAsVariant[0] == 1);
|
||||
assert(variantArrayAsVariant.length == 3);
|
||||
|
||||
// array tests
|
||||
auto arr = Variant([1.2].dup);
|
||||
|
@ -829,7 +994,7 @@ unittest
|
|||
// assign
|
||||
a = *b.peek!(int);
|
||||
// comparison
|
||||
assert(a == b);
|
||||
assert(a == b, a.type.toString ~ " " ~ b.type.toString);
|
||||
auto c = Variant("this is a string");
|
||||
assert(a != c);
|
||||
// comparison via implicit conversions
|
||||
|
@ -889,12 +1054,12 @@ unittest
|
|||
|
||||
// should be string... @@@BUG IN COMPILER
|
||||
v = "Hello, World!"c;
|
||||
assert( v.peek!(char[]) );
|
||||
assert( v.peek!(string) );
|
||||
|
||||
assert( v.get!(char[]) == "Hello, World!" );
|
||||
assert( v.get!(string) == "Hello, World!" );
|
||||
assert(!is(char[] : wchar[]));
|
||||
assert( !v.convertsTo!(wchar[]) );
|
||||
assert( v.get!(char[]) == "Hello, World!" );
|
||||
assert( v.get!(string) == "Hello, World!" );
|
||||
|
||||
v = [1,2,3,4,5];
|
||||
assert( v.peek!(int[]) );
|
||||
|
@ -987,24 +1152,3 @@ unittest
|
|||
assert( vhash.get!(int[char[]])["c"] == 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Algebraic data type restricted to a closed set of possible
|
||||
* types. It's an alias for a $(D_PARAM VariantN) with an
|
||||
* appropriately-constructed maximum size.
|
||||
*
|
||||
* Example:
|
||||
* ----
|
||||
* auto v = Algebraic!(int, double, string)(5);
|
||||
* assert(v.peek!(int));
|
||||
* v = 3.14;
|
||||
* assert(v.peek!(double));
|
||||
* // auto x = peek!(long); // won't compile, type long not allowed
|
||||
* // v = '1'; // won't compile, type char not allowed
|
||||
* ----
|
||||
*/
|
||||
|
||||
template Algebraic(T...)
|
||||
{
|
||||
alias VariantN!(maxSize!(T), T) Algebraic;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ module std.zip;
|
|||
private import std.zlib;
|
||||
private import std.date;
|
||||
private import std.intrinsic;
|
||||
import std.conv;
|
||||
|
||||
//debug=print;
|
||||
|
||||
|
@ -30,7 +31,7 @@ class ZipException : Exception
|
|||
{
|
||||
this(string msg)
|
||||
{
|
||||
super(cast(string) ("ZipException: " ~ msg));
|
||||
super("ZipException: " ~ msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +318,7 @@ class ZipArchive
|
|||
endcommentlength = getUshort(i + 20);
|
||||
if (i + 22 + endcommentlength > data.length)
|
||||
continue;
|
||||
comment = cast(string)data[i + 22 .. i + 22 + endcommentlength];
|
||||
comment = to!(string)(data[i + 22 .. i + 22 + endcommentlength]);
|
||||
endrecOffset = i;
|
||||
break;
|
||||
}
|
||||
|
@ -378,11 +379,11 @@ class ZipArchive
|
|||
if (i + namelen + extralen + commentlen > directoryOffset + directorySize)
|
||||
throw new ZipException("invalid directory entry 2");
|
||||
|
||||
de.name = cast(string)data[i .. i + namelen];
|
||||
de.name = to!(string)(data[i .. i + namelen]);
|
||||
i += namelen;
|
||||
de.extra = data[i .. i + extralen];
|
||||
i += extralen;
|
||||
de.comment = cast(string)data[i .. i + commentlen];
|
||||
de.comment = to!(string)(data[i .. i + commentlen]);
|
||||
i += commentlen;
|
||||
|
||||
directory[de.name] = de;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue