mirror of
https://github.com/dlang/phobos.git
synced 2025-04-27 05:30:33 +03:00
phobos 0.124
This commit is contained in:
parent
659864e3f6
commit
fab6cdaa9f
7 changed files with 776 additions and 9 deletions
|
@ -56,7 +56,7 @@ OBJS= asserterror.o deh2.o switch.o complex.o gcstats.o \
|
|||
crc32.o conv.o arraycast.o errno.o alloca.o cmath2.o \
|
||||
process.o syserror.o \
|
||||
socket.o socketstream.o stdarg.o stdio.o format.o \
|
||||
perf.o openrj.o uni.o trace.o \
|
||||
perf.o openrj.o uni.o trace.o boxer.o \
|
||||
ti_wchar.o ti_uint.o ti_short.o ti_ushort.o \
|
||||
ti_byte.o ti_ubyte.o ti_long.o ti_ulong.o ti_ptr.o \
|
||||
ti_float.o ti_double.o ti_real.o ti_delegate.o \
|
||||
|
@ -98,7 +98,8 @@ SRC_STD= std/zlib.d std/zip.d std/stdint.d std/conv.d std/utf.d std/uri.d \
|
|||
std/intrinsic.d std/array.d std/switcherr.d std/syserror.d \
|
||||
std/regexp.d std/random.d std/stream.d std/process.d std/recls.d \
|
||||
std/socket.d std/socketstream.d std/loader.d std/stdarg.d \
|
||||
std/stdio.d std/format.d std/perf.d std/openrj.d std/uni.d
|
||||
std/stdio.d std/format.d std/perf.d std/openrj.d std/uni.d \
|
||||
std/boxer.d
|
||||
|
||||
SRC_STD_C= std/c/process.d std/c/stdlib.d std/c/time.d std/c/stdio.d \
|
||||
std/c/math.d std/c/stdarg.d std/c/stddef.d
|
||||
|
@ -471,6 +472,9 @@ asserterror.o : std/asserterror.d
|
|||
base64.o : std/base64.d
|
||||
$(DMD) -c $(DFLAGS) std/base64.d
|
||||
|
||||
boxer.o : std/boxer.d
|
||||
$(DMD) -c $(DFLAGS) std/boxer.d
|
||||
|
||||
compiler.o : std/compiler.d
|
||||
$(DMD) -c $(DFLAGS) std/compiler.d
|
||||
|
||||
|
|
755
std/boxer.d
Normal file
755
std/boxer.d
Normal file
|
@ -0,0 +1,755 @@
|
|||
/* This module is written by Burton Radons and placed into the public domain. */
|
||||
module std.boxer;
|
||||
|
||||
private import std.format;
|
||||
private import std.string;
|
||||
private import std.utf;
|
||||
|
||||
/** These functions and types allow packing objects into generic containers
|
||||
* and recovering them later. This comes into play in a wide spectrum of
|
||||
* utilities, such as with a scripting language, or as additional user data
|
||||
* for an object.
|
||||
*
|
||||
* Box an object by calling the box function:
|
||||
*
|
||||
* Box x = box(4);
|
||||
*
|
||||
* Recover the value by using the unbox template:
|
||||
*
|
||||
* int y = unbox!(int)(x);
|
||||
*
|
||||
* If it cannot unbox the object to that type, it throws UnboxException. It will
|
||||
* use implicit casts to behave in the exact same way as D does - for
|
||||
* instance:
|
||||
*
|
||||
* byte v;
|
||||
* int i = v; // Implicitly cast from byte to int.
|
||||
* int j = unbox!(int)(Box(i)); // Do the exact same thing at runtime.
|
||||
*
|
||||
* This therefore means that attempting to unbox an int as a string will
|
||||
* throw an error and not format it. In general, you can call the toString
|
||||
* method on the box and receive a good result, depending upon whether
|
||||
* std.string.format accepts it.
|
||||
*
|
||||
* Boxes can be compared to one another and they can be used as keys for
|
||||
* associative arrays. Boxes of different types can be compared to one
|
||||
* another, using the same casting rules as the main type system.
|
||||
*
|
||||
* boxArray has two forms:
|
||||
*
|
||||
* Box[] boxArray(...);
|
||||
* Box[] boxArray(TypeInfo[] types, void* data);
|
||||
*
|
||||
* This converts an array of arguments into an array of boxes. To convert
|
||||
* back into an array of arguments, use boxArrayToArguments:
|
||||
*
|
||||
* void boxArrayToArguments(Box[] arguments, out TypeInfo[] types,
|
||||
* out void[] data);
|
||||
*
|
||||
* Finally, you can discover whether unboxing as a certain type is legal by
|
||||
* using the unboxable template or method:
|
||||
*
|
||||
* bit unboxable!(T) (Box value);
|
||||
* bit Box.unboxable(TypeInfo T);
|
||||
*/
|
||||
|
||||
/** Return the next type in an array typeinfo, or null if there is none. */
|
||||
private bit isArrayTypeInfo(TypeInfo type)
|
||||
{
|
||||
char[] name = type.classinfo.name;
|
||||
return name.length >= 10 && name[9] == 'A' && name != "TypeInfo_AssociativeArray";
|
||||
}
|
||||
|
||||
/** The type class returned from Box.findTypeClass; the order of entries is important. */
|
||||
private enum TypeClass
|
||||
{
|
||||
Bit, /**< bit */
|
||||
Integer, /**< byte, ubyte, short, ushort, int, uint, long, ulong */
|
||||
Float, /**< float, double, real */
|
||||
Complex, /**< cfloat, cdouble, creal */
|
||||
Imaginary, /**< ifloat, idouble, ireal */
|
||||
Class, /**< Inherits from Object */
|
||||
Pointer, /**< Pointer type (T *) */
|
||||
Array, /**< Array type (T []) */
|
||||
Other, /**< Any other type, such as delegates, function pointers, struct, void... */
|
||||
}
|
||||
|
||||
/** A box object contains a value in a generic fashion, allowing it to be
|
||||
* passed from one place to another without having to know its type. It is
|
||||
* created by calling the box function, and you can recover the value by
|
||||
* instantiating the unbox template.
|
||||
*/
|
||||
struct Box
|
||||
{
|
||||
private TypeInfo p_type; /**< The type of the contained object. */
|
||||
|
||||
private union
|
||||
{
|
||||
void* p_longData; /**< An array of the contained object. */
|
||||
void[8] p_shortData; /**< Data used when the object is small. */
|
||||
}
|
||||
|
||||
private static TypeClass findTypeClass(TypeInfo type)
|
||||
{
|
||||
if (cast(TypeInfo_Class) type)
|
||||
return TypeClass.Class;
|
||||
if (cast(TypeInfo_Pointer) type)
|
||||
return TypeClass.Pointer;
|
||||
if (isArrayTypeInfo(type))
|
||||
return TypeClass.Array;
|
||||
|
||||
version (DigitalMars)
|
||||
{
|
||||
/* Depend upon the name of the base type classes. */
|
||||
if (type.classinfo.name.length != "TypeInfo_?".length)
|
||||
return TypeClass.Other;
|
||||
switch (type.classinfo.name[9])
|
||||
{
|
||||
case 'b': return TypeClass.Bit;
|
||||
case 'g', 'h', 's', 't', 'i', 'k', 'l', 'm': return TypeClass.Integer;
|
||||
case 'f', 'd', 'e': return TypeClass.Float;
|
||||
case 'q', 'r', 'c': return TypeClass.Complex;
|
||||
case 'o', 'p', 'j': return TypeClass.Imaginary;
|
||||
default: return TypeClass.Other;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the name returned from toString, which might (but hopefully doesn't) include an allocation. */
|
||||
switch (type.toString)
|
||||
{
|
||||
case "bit": return TypeClass.Bit;
|
||||
case "byte", "ubyte", "short", "ushort", "int", "uint", "long", "ulong": return TypeClass.Integer;
|
||||
case "float", "real", "double": return TypeClass.Float;
|
||||
case "cfloat", "cdouble", "creal": return TypeClass.Complex;
|
||||
case "ifloat", "idouble", "ireal": return TypeClass.Imaginary;
|
||||
default: return TypeClass.Other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Return whether this value could be unboxed as the given type without throwing. */
|
||||
bit unboxable(TypeInfo test)
|
||||
{
|
||||
if (type is test)
|
||||
return true;
|
||||
|
||||
TypeInfo_Class ca = cast(TypeInfo_Class) type, cb = cast(TypeInfo_Class) test;
|
||||
|
||||
if (ca !== null && cb !== null)
|
||||
{
|
||||
ClassInfo ia = (*cast(Object *) data).classinfo, ib = cb.info;
|
||||
|
||||
for ( ; ia !== null; ia = ia.base)
|
||||
if (ia is ib)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeClass ta = findTypeClass(type), tb = findTypeClass(test);
|
||||
|
||||
if (type is typeid(void*) && *cast(void**) data is null)
|
||||
return (tb == TypeClass.Class || tb == TypeClass.Pointer || tb == TypeClass.Array);
|
||||
|
||||
if (test is typeid(void*))
|
||||
return (tb == TypeClass.Class || tb == TypeClass.Pointer || tb == TypeClass.Array);
|
||||
|
||||
if (ta == TypeClass.Pointer && tb == TypeClass.Pointer)
|
||||
return (cast(TypeInfo_Pointer)type).next is (cast(TypeInfo_Pointer)test).next;
|
||||
|
||||
if ((ta == tb && ta != TypeClass.Other)
|
||||
|| (ta == TypeClass.Bit && tb == TypeClass.Integer)
|
||||
|| (ta <= TypeClass.Integer && tb == TypeClass.Float)
|
||||
|| (ta <= TypeClass.Imaginary && tb == TypeClass.Complex))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Return the type of the contained object. */
|
||||
TypeInfo type()
|
||||
{
|
||||
return p_type;
|
||||
}
|
||||
|
||||
/** Return the data array. */
|
||||
void[] data()
|
||||
{
|
||||
size_t size = type.tsize();
|
||||
|
||||
return size <= p_shortData.length ? p_shortData[0..size] : p_longData[0..size];
|
||||
}
|
||||
|
||||
/** Attempt to convert the object to a string by doing D formatting on it.
|
||||
*/
|
||||
char[] toString()
|
||||
{
|
||||
if (type is null)
|
||||
return "<empty box>";
|
||||
|
||||
TypeInfo[2] arguments;
|
||||
char[] string;
|
||||
void[] args = new void[(char[]).sizeof + data.length];
|
||||
char[] format = "%s";
|
||||
|
||||
arguments[0] = typeid(char[]);
|
||||
arguments[1] = type;
|
||||
|
||||
void putc(dchar ch)
|
||||
{
|
||||
std.utf.encode(string, ch);
|
||||
}
|
||||
|
||||
args[0..(char[]).sizeof] = (cast(void*) &format)[0..(char[]).sizeof];
|
||||
args[(char[]).sizeof..length] = data;
|
||||
std.format.doFormat(&putc, arguments, args);
|
||||
delete args;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
private bit opEqualsInternal(Box other, bit inverted)
|
||||
{
|
||||
if (type != other.type)
|
||||
{
|
||||
if (!unboxable(other.type))
|
||||
{
|
||||
if (inverted)
|
||||
return false;
|
||||
return other.opEqualsInternal(*this, true);
|
||||
}
|
||||
|
||||
TypeClass ta = findTypeClass(type), tb = findTypeClass(other.type);
|
||||
|
||||
if (ta <= TypeClass.Integer && tb <= TypeClass.Integer)
|
||||
{
|
||||
char[] na = type.toString, nb = other.type.toString;
|
||||
|
||||
if (na == "ulong" || nb == "ulong")
|
||||
return unbox!(ulong)(*this) == unbox!(ulong)(other);
|
||||
return unbox!(long)(*this) == unbox!(long)(other);
|
||||
}
|
||||
else if (tb == TypeClass.Float)
|
||||
return unbox!(real)(*this) == unbox!(real)(other);
|
||||
else if (tb == TypeClass.Complex)
|
||||
return unbox!(creal)(*this) == unbox!(creal)(other);
|
||||
else if (tb == TypeClass.Imaginary)
|
||||
return unbox!(ireal)(*this) == unbox!(ireal)(other);
|
||||
|
||||
assert (0);
|
||||
}
|
||||
|
||||
return cast(bit)type.equals(data, other.data);
|
||||
}
|
||||
|
||||
/** Implement the equals operator. */
|
||||
bit opEquals(Box other)
|
||||
{
|
||||
return opEqualsInternal(other, false);
|
||||
}
|
||||
|
||||
private float opCmpInternal(Box other, bit inverted)
|
||||
{
|
||||
if (type != other.type)
|
||||
{
|
||||
if (!unboxable(other.type))
|
||||
{
|
||||
if (inverted)
|
||||
return 0;
|
||||
return other.opCmpInternal(*this, true);
|
||||
}
|
||||
|
||||
TypeClass ta = findTypeClass(type), tb = findTypeClass(other.type);
|
||||
|
||||
if (ta <= TypeClass.Integer && tb == TypeClass.Integer)
|
||||
{
|
||||
if (type == typeid(ulong) || other.type == typeid(ulong))
|
||||
{
|
||||
ulong va = unbox!(ulong)(*this), vb = unbox!(ulong)(other);
|
||||
return va > vb ? 1 : va < vb ? -1 : 0;
|
||||
}
|
||||
|
||||
long va = unbox!(long)(*this), vb = unbox!(long)(other);
|
||||
return va > vb ? 1 : va < vb ? -1 : 0;
|
||||
}
|
||||
else if (tb == TypeClass.Float)
|
||||
{
|
||||
real va = unbox!(real)(*this), vb = unbox!(real)(other);
|
||||
return va > vb ? 1 : va < vb ? -1 : va == vb ? 0 : float.nan;
|
||||
}
|
||||
else if (tb == TypeClass.Complex)
|
||||
{
|
||||
creal va = unbox!(creal)(*this), vb = unbox!(creal)(other);
|
||||
return va == vb ? 0 : float.nan;
|
||||
}
|
||||
else if (tb == TypeClass.Imaginary)
|
||||
{
|
||||
ireal va = unbox!(ireal)(*this), vb = unbox!(ireal)(other);
|
||||
return va > vb ? 1 : va < vb ? -1 : va == vb ? 0 : float.nan;
|
||||
}
|
||||
|
||||
assert (0);
|
||||
}
|
||||
|
||||
return type.compare(data, other.data);
|
||||
}
|
||||
|
||||
/** Implement the compare operator. */
|
||||
float opCmp(Box other)
|
||||
{
|
||||
return opCmpInternal(other, false);
|
||||
}
|
||||
|
||||
uint toHash()
|
||||
{
|
||||
return type.getHash(data);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a box out of the first argument passed. */
|
||||
Box box(...)
|
||||
in
|
||||
{
|
||||
assert (_arguments.length == 1);
|
||||
}
|
||||
body
|
||||
{
|
||||
return box(_arguments[0], _argptr);
|
||||
}
|
||||
|
||||
/** Assign the parameters, copying data as needed. */
|
||||
Box box(TypeInfo type, void* data)
|
||||
in
|
||||
{
|
||||
assert(type !== null);
|
||||
}
|
||||
body
|
||||
{
|
||||
Box result;
|
||||
size_t size = type.tsize();
|
||||
|
||||
result.p_type = type;
|
||||
if (size <= result.p_shortData.length)
|
||||
result.p_shortData[0..size] = data[0..size];
|
||||
else
|
||||
result.p_longData = data[0..size].dup;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Return the length of an argument in bytes. */
|
||||
private size_t argumentLength(size_t baseLength)
|
||||
{
|
||||
return (baseLength + int.sizeof - 1) & ~(int.sizeof - 1);
|
||||
}
|
||||
|
||||
/** Box each argument in the list. */
|
||||
Box[] boxArray(TypeInfo[] types, void* data)
|
||||
{
|
||||
Box[] array = new Box[types.length];
|
||||
|
||||
foreach(size_t index, TypeInfo type; types)
|
||||
{
|
||||
array[index] = box(type, data);
|
||||
data += argumentLength(type.tsize());
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/** Box each argument passed to the function, returning an array of boxes. */
|
||||
Box[] boxArray(...)
|
||||
{
|
||||
return boxArray(_arguments, _argptr);
|
||||
}
|
||||
|
||||
/** Convert an array of boxes into an array of arguments. */
|
||||
void boxArrayToArguments(Box[] arguments, out TypeInfo[] types, out void* data)
|
||||
{
|
||||
size_t dataLength;
|
||||
void* pointer;
|
||||
|
||||
/* Determine the number of bytes of data to allocate by summing the arguments. */
|
||||
foreach (Box item; arguments)
|
||||
dataLength += argumentLength(item.data.length);
|
||||
|
||||
types = new TypeInfo[arguments.length];
|
||||
pointer = data = new void[dataLength];
|
||||
|
||||
/* Stash both types and data. */
|
||||
foreach (size_t index, Box item; arguments)
|
||||
{
|
||||
types[index] = item.type;
|
||||
pointer[0..item.data.length] = item.data;
|
||||
pointer += argumentLength(item.data.length);
|
||||
}
|
||||
}
|
||||
|
||||
/** This is thrown if you try to unbox an incompatible type. */
|
||||
class UnboxException : Exception
|
||||
{
|
||||
/** The boxed object spawning the error. */
|
||||
Box object;
|
||||
|
||||
/** The type that we tried to unbox as. */
|
||||
TypeInfo outputType;
|
||||
|
||||
/** Assign parameters and the message. */
|
||||
this(Box object, TypeInfo outputType)
|
||||
{
|
||||
this.object = object;
|
||||
this.outputType = outputType;
|
||||
super(format("Could not unbox from type %s to %s.", object.type, outputType));
|
||||
}
|
||||
}
|
||||
|
||||
/** A generic unboxer for the real numeric types. */
|
||||
private template unboxCastReal(T)
|
||||
{
|
||||
T unboxCastReal(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (value.type is typeid(float))
|
||||
return cast(T) *cast(float*) value.data;
|
||||
if (value.type is typeid(double))
|
||||
return cast(T) *cast(double*) value.data;
|
||||
if (value.type is typeid(real))
|
||||
return cast(T) *cast(real*) value.data;
|
||||
return unboxCastInteger!(T)(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** A generic unboxer for the integral numeric types. */
|
||||
private template unboxCastInteger(T)
|
||||
{
|
||||
T unboxCastInteger(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (value.type is typeid(int))
|
||||
return cast(T) *cast(int*) value.data;
|
||||
if (value.type is typeid(uint))
|
||||
return cast(T) *cast(uint*) value.data;
|
||||
if (value.type is typeid(long))
|
||||
return cast(T) *cast(long*) value.data;
|
||||
if (value.type is typeid(ulong))
|
||||
return cast(T) *cast(ulong*) value.data;
|
||||
if (value.type is typeid(bit))
|
||||
return cast(T) *cast(bit*) value.data;
|
||||
if (value.type is typeid(byte))
|
||||
return cast(T) *cast(byte*) value.data;
|
||||
if (value.type is typeid(ubyte))
|
||||
return cast(T) *cast(ubyte*) value.data;
|
||||
if (value.type is typeid(short))
|
||||
return cast(T) *cast(short*) value.data;
|
||||
if (value.type is typeid(ushort))
|
||||
return cast(T) *cast(ushort*) value.data;
|
||||
throw new UnboxException(value, typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
/** A generic unboxer for the complex numeric types. */
|
||||
private template unboxCastComplex(T)
|
||||
{
|
||||
T unboxCastComplex(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (value.type is typeid(cfloat))
|
||||
return cast(T) *cast(cfloat*) value.data;
|
||||
if (value.type is typeid(cdouble))
|
||||
return cast(T) *cast(cdouble*) value.data;
|
||||
if (value.type is typeid(creal))
|
||||
return cast(T) *cast(creal*) value.data;
|
||||
if (value.type is typeid(ifloat))
|
||||
return cast(T) *cast(ifloat*) value.data;
|
||||
if (value.type is typeid(idouble))
|
||||
return cast(T) *cast(idouble*) value.data;
|
||||
if (value.type is typeid(ireal))
|
||||
return cast(T) *cast(ireal*) value.data;
|
||||
return unboxCastReal!(T)(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** A generic unboxer for the imaginary numeric types. */
|
||||
private template unboxCastImaginary(T)
|
||||
{
|
||||
T unboxCastImaginary(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (value.type is typeid(ifloat))
|
||||
return cast(T) *cast(ifloat*) value.data;
|
||||
if (value.type is typeid(idouble))
|
||||
return cast(T) *cast(idouble*) value.data;
|
||||
if (value.type is typeid(ireal))
|
||||
return cast(T) *cast(ireal*) value.data;
|
||||
throw new UnboxException(value, typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
/** This unbox template takes a template parameter and returns a function that
|
||||
* takes a box object and returns the specified type. If it cannot cast to
|
||||
* the type, it throws UnboxException. For example:
|
||||
*
|
||||
* Box y = box(4);
|
||||
* int x = unbox!(int) (y);
|
||||
*/
|
||||
template unbox(T)
|
||||
{
|
||||
T unbox(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (typeid(T) is value.type)
|
||||
return *cast(T*) value.data;
|
||||
throw new UnboxException(value, typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
template unbox(T : byte) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : ubyte) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : short) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : ushort) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : int) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : uint) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : long) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : ulong) { T unbox(Box value) { return unboxCastInteger!(T) (value); } }
|
||||
template unbox(T : float) { T unbox(Box value) { return unboxCastReal!(T) (value); } }
|
||||
template unbox(T : double) { T unbox(Box value) { return unboxCastReal!(T) (value); } }
|
||||
template unbox(T : real) { T unbox(Box value) { return unboxCastReal!(T) (value); } }
|
||||
template unbox(T : cfloat) { T unbox(Box value) { return unboxCastComplex!(T) (value); } }
|
||||
template unbox(T : cdouble) { T unbox(Box value) { return unboxCastComplex!(T) (value); } }
|
||||
template unbox(T : creal) { T unbox(Box value) { return unboxCastComplex!(T) (value); } }
|
||||
template unbox(T : ifloat) { T unbox(Box value) { return unboxCastImaginary!(T) (value); } }
|
||||
template unbox(T : idouble) { T unbox(Box value) { return unboxCastImaginary!(T) (value); } }
|
||||
template unbox(T : ireal) { T unbox(Box value) { return unboxCastImaginary!(T) (value); } }
|
||||
|
||||
template unbox(T : Object)
|
||||
{
|
||||
T unbox(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (typeid(T) == value.type || cast(TypeInfo_Class) value.type)
|
||||
{
|
||||
Object object = *cast(Object*)value.data;
|
||||
T result = cast(T)object;
|
||||
|
||||
if (object is null)
|
||||
return null;
|
||||
if (result is null)
|
||||
throw new UnboxException(value, typeid(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (typeid(void*) is value.type && *cast(void**) value.data is null)
|
||||
return null;
|
||||
throw new UnboxException(value, typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
template unbox(T : T[])
|
||||
{
|
||||
T[] unbox(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (typeid(T[]) is value.type)
|
||||
return *cast(T[]*) value.data;
|
||||
if (typeid(void*) is value.type && *cast(void**) value.data is null)
|
||||
return null;
|
||||
throw new UnboxException(value, typeid(T[]));
|
||||
}
|
||||
}
|
||||
|
||||
template unbox(T : T*)
|
||||
{
|
||||
T* unbox(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (typeid(T*) is value.type)
|
||||
return *cast(T**) value.data;
|
||||
if (typeid(void*) is value.type && *cast(void**) value.data is null)
|
||||
return null;
|
||||
if (typeid(T[]) is value.type)
|
||||
return *cast(T[]*) value.data;
|
||||
|
||||
throw new UnboxException(value, typeid(T*));
|
||||
}
|
||||
}
|
||||
|
||||
template unbox(T : void*)
|
||||
{
|
||||
T unbox(Box value)
|
||||
{
|
||||
assert (value.type !== null);
|
||||
|
||||
if (cast(TypeInfo_Pointer) value.type)
|
||||
return *cast(void**) value.data;
|
||||
if (isArrayTypeInfo(value.type))
|
||||
return *cast(void[]*) value.data;
|
||||
if (typeid(Object) == value.type)
|
||||
return *cast(Object*) value.data;
|
||||
|
||||
throw new UnboxException(value, typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
/** Return whether the value can be unboxed to this type without throwing
|
||||
* UnboxException.
|
||||
*/
|
||||
template unboxable(T)
|
||||
{
|
||||
bit unboxable(Box value)
|
||||
{
|
||||
return value.unboxable(typeid(T));
|
||||
}
|
||||
}
|
||||
|
||||
/* Tests unboxing - assert that if it says it's unboxable, it is. */
|
||||
private template unboxTest(T)
|
||||
{
|
||||
T unboxTest(Box value)
|
||||
{
|
||||
T result;
|
||||
bit unboxable = value.unboxable(typeid(T));
|
||||
|
||||
try result = unbox!(T) (value);
|
||||
catch (UnboxException error)
|
||||
{
|
||||
if (unboxable)
|
||||
throw new Error ("Could not unbox " ~ value.type.toString ~ " as " ~ typeid(T).toString ~ "; however, unboxable says it would work.");
|
||||
assert (!unboxable);
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!unboxable)
|
||||
throw new Error ("Unboxed " ~ value.type.toString ~ " as " ~ typeid(T).toString ~ "; however, unboxable says it should fail.");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
class A { }
|
||||
class B : A { }
|
||||
struct SA { }
|
||||
struct SB { }
|
||||
|
||||
Box a, b;
|
||||
|
||||
/* Call the function, catch UnboxException, return that it threw correctly. */
|
||||
bit fails(void delegate()func)
|
||||
{
|
||||
try func();
|
||||
catch (UnboxException error)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that equals and comparison work properly. */
|
||||
a = box(0);
|
||||
b = box(32);
|
||||
assert (a != b);
|
||||
assert (a == a);
|
||||
assert (a < b);
|
||||
|
||||
/* Check that toString works properly. */
|
||||
assert (b.toString == "32");
|
||||
|
||||
/* Assert that unboxable works. */
|
||||
assert (unboxable!(char[])(box("foobar")));
|
||||
|
||||
/* Assert that we can cast from int to byte. */
|
||||
assert (unboxTest!(byte)(b) == 32);
|
||||
|
||||
/* Assert that we can cast from int to real. */
|
||||
assert (unboxTest!(real)(b) == 32.0L);
|
||||
|
||||
/* Check that real works properly. */
|
||||
assert (unboxTest!(real)(box(32.45L)) == 32.45L);
|
||||
|
||||
/* Assert that we cannot implicitly cast from real to int. */
|
||||
assert(fails(delegate void() { unboxTest!(int)(box(1.3)); }));
|
||||
|
||||
/* Check that the unspecialized unbox template works. */
|
||||
assert(unboxTest!(char[])(box("foobar")) == "foobar");
|
||||
|
||||
/* Assert that complex works correctly. */
|
||||
assert(unboxTest!(cdouble)(box(1 + 2i)) == 1 + 2i);
|
||||
|
||||
/* Assert that imaginary works correctly. */
|
||||
assert(unboxTest!(ireal)(box(45i)) == 45i);
|
||||
|
||||
/* Create an array of boxes from arguments. */
|
||||
Box[] array = boxArray(16, "foobar", new Object);
|
||||
|
||||
assert(array.length == 3);
|
||||
assert(unboxTest!(int)(array[0]) == 16);
|
||||
assert(unboxTest!(char[])(array[1]) == "foobar");
|
||||
assert(unboxTest!(Object)(array[2]) !== null);
|
||||
|
||||
/* Convert the box array back into arguments. */
|
||||
TypeInfo[] array_types;
|
||||
void* array_data;
|
||||
|
||||
boxArrayToArguments(array, array_types, array_data);
|
||||
assert (array_types.length == 3);
|
||||
|
||||
/* Confirm the symmetry. */
|
||||
assert (boxArray(array_types, array_data) == array);
|
||||
|
||||
/* Assert that we can cast from int to creal. */
|
||||
assert (unboxTest!(creal)(box(45)) == 45+0i);
|
||||
|
||||
/* Assert that we can cast from idouble to creal. */
|
||||
assert (unboxTest!(creal)(box(45i)) == 0+45i);
|
||||
|
||||
/* Assert that equality testing casts properly. */
|
||||
assert (box(1) == box(cast(byte)1));
|
||||
assert (box(cast(real)4) == box(4));
|
||||
assert (box(5) == box(5+0i));
|
||||
assert (box(0+4i) == box(4i));
|
||||
assert (box(8i) == box(0+8i));
|
||||
|
||||
/* Assert that comparisons cast properly. */
|
||||
assert (box(450) < box(451));
|
||||
assert (box(4) > box(3.0));
|
||||
assert (box(0+3i) < box(0+4i));
|
||||
|
||||
/* Assert that casting from bit to int works. */
|
||||
assert (1 == unboxTest!(int)(box(true)));
|
||||
assert (box(1) == box(true));
|
||||
|
||||
/* Assert that unboxing to an object works properly. */
|
||||
assert (unboxTest!(B)(box(cast(A)new B)) !== null);
|
||||
|
||||
/* Assert that illegal object casting fails properly. */
|
||||
assert (fails(delegate void() { unboxTest!(B)(box(new A)); }));
|
||||
|
||||
/* Assert that we can unbox a null. */
|
||||
assert (unboxTest!(A)(box(cast(A)null)) is null);
|
||||
assert (unboxTest!(A)(box(null)) is null);
|
||||
|
||||
/* Unboxing null in various contexts. */
|
||||
assert (unboxTest!(char[])(box(null)) is null);
|
||||
assert (unboxTest!(int*)(box(null)) is null);
|
||||
|
||||
/* Assert that unboxing between pointer types fails. */
|
||||
int [1] p;
|
||||
assert (fails(delegate void() { unboxTest!(char*)(box(p.ptr)); }));
|
||||
|
||||
/* Assert that unboxing various types as void* does work. */
|
||||
assert (unboxTest!(void*)(box(p.ptr))); // int*
|
||||
assert (unboxTest!(void*)(box(p))); // int[]
|
||||
assert (unboxTest!(void*)(box(new A))); // Object
|
||||
|
||||
/* Assert that we can't unbox an integer as bit. */
|
||||
assert (!unboxable!(bit) (box(4)));
|
||||
|
||||
/* Assert that we can't unbox a struct as another struct. */
|
||||
SA sa;
|
||||
assert (!unboxable!(SB)(box(sa)));
|
||||
}
|
|
@ -1387,7 +1387,7 @@ class BufferedStream : Stream {
|
|||
throw new WriteException("Unable to write to stream");
|
||||
}
|
||||
}
|
||||
long diff = bufferCurPos-bufferSourcePos;
|
||||
long diff = cast(long)bufferCurPos-bufferSourcePos;
|
||||
if (diff != 0 && seekable) {
|
||||
// move actual file pointer to current position
|
||||
streamPos = s.seek(diff, SeekPos.Current);
|
||||
|
@ -1417,7 +1417,7 @@ class BufferedStream : Stream {
|
|||
|
||||
// returns size of stream
|
||||
ulong size() {
|
||||
flush();
|
||||
if (bufferDirty) flush();
|
||||
return s.size();
|
||||
}
|
||||
|
||||
|
@ -1785,12 +1785,17 @@ class BufferedFile: BufferedStream {
|
|||
assert(file.position() == 18 + 13 + 4);
|
||||
// we must be at the end of file
|
||||
assert(file.eof());
|
||||
long oldsize = file.size();
|
||||
file.close();
|
||||
// no operations are allowed when file is closed
|
||||
assert(!file.readable && !file.writeable && !file.seekable);
|
||||
file.open("stream.$$$");
|
||||
// should be ok to read
|
||||
assert(file.readable);
|
||||
// test getc/ungetc and size()
|
||||
char c1 = file.getc();
|
||||
file.ungetc(c1);
|
||||
assert( file.size() == oldsize );
|
||||
assert(!std.string.cmp(file.readLine(), "Testing stream.d:"));
|
||||
// jump over "Hello, "
|
||||
file.seek(7, SeekPos.Current);
|
||||
|
|
|
@ -1374,6 +1374,7 @@ unittest
|
|||
/**************************************
|
||||
* Split s[] into an array of lines,
|
||||
* using CR, LF, or CR-LF as the delimiter.
|
||||
* The delimiter is not included in the line.
|
||||
*/
|
||||
|
||||
char[][] splitlines(char[] s)
|
||||
|
|
|
@ -13,13 +13,11 @@ class TypeInfo_v : TypeInfo
|
|||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
assert(0);
|
||||
return *cast(byte *)p1 == *cast(byte *)p2;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
assert(0);
|
||||
return *cast(byte *)p1 - *cast(byte *)p2;
|
||||
}
|
||||
|
||||
|
@ -32,7 +30,6 @@ class TypeInfo_v : TypeInfo
|
|||
{
|
||||
byte t;
|
||||
|
||||
assert(0);
|
||||
t = *cast(byte *)p1;
|
||||
*cast(byte *)p1 = *cast(byte *)p2;
|
||||
*cast(byte *)p2 = t;
|
||||
|
|
|
@ -44,6 +44,7 @@ import std.zlib;
|
|||
import std.md5;
|
||||
import std.stdio;
|
||||
import std.conv;
|
||||
import std.boxer;
|
||||
|
||||
int main(char[][] args)
|
||||
{
|
||||
|
@ -76,6 +77,7 @@ printf("test2\n");
|
|||
|
||||
writefln("hello world!"); // std.format
|
||||
|
||||
Box abox;
|
||||
{
|
||||
creal c = 3.0 + 4.0i;
|
||||
c = sqrt(c);
|
||||
|
|
|
@ -65,7 +65,7 @@ OBJS= asserterror.obj deh.obj switch.obj complex.obj gcstats.obj \
|
|||
Czlib.obj Dzlib.obj zip.obj process.obj registry.obj recls.obj \
|
||||
socket.obj socketstream.obj loader.obj stdarg.obj format.obj stdio.obj \
|
||||
perf.obj openrj.obj uni.obj winsock.obj oldsyserror.obj \
|
||||
errno.obj \
|
||||
errno.obj boxer.obj \
|
||||
ti_Aa.obj ti_Ag.obj ti_C.obj ti_int.obj ti_char.obj \
|
||||
ti_wchar.obj ti_uint.obj ti_short.obj ti_ushort.obj \
|
||||
ti_byte.obj ti_ubyte.obj ti_long.obj ti_ulong.obj ti_ptr.obj \
|
||||
|
@ -90,7 +90,7 @@ SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.d \
|
|||
std\intrinsic.d std\array.d std\switcherr.d std\syserror.d \
|
||||
std\regexp.d std\random.d std\stream.d std\process.d std\recls.d \
|
||||
std\socket.d std\socketstream.d std\loader.d std\stdarg.d std\format.d \
|
||||
std\stdio.d std\perf.d std\openrj.d std\uni.d
|
||||
std\stdio.d std\perf.d std\openrj.d std\uni.d std\boxer.d
|
||||
|
||||
SRC_STD_C= std\c\process.d std\c\stdlib.d std\c\time.d std\c\stdio.d \
|
||||
std\c\math.d std\c\stdarg.d std\c\stddef.d
|
||||
|
@ -436,6 +436,9 @@ asserterror.obj : std\asserterror.d
|
|||
base64.obj : std\base64.d
|
||||
$(DMD) -c $(DFLAGS) -inline std\base64.d
|
||||
|
||||
boxer.obj : std\boxer.d
|
||||
$(DMD) -c $(DFLAGS) std\boxer.d
|
||||
|
||||
compiler.obj : std\compiler.d
|
||||
$(DMD) -c $(DFLAGS) std\compiler.d
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue