phobos 0.124

This commit is contained in:
Brad Roberts 2007-09-10 04:42:45 +00:00
parent 659864e3f6
commit fab6cdaa9f
7 changed files with 776 additions and 9 deletions

View file

@ -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 \ crc32.o conv.o arraycast.o errno.o alloca.o cmath2.o \
process.o syserror.o \ process.o syserror.o \
socket.o socketstream.o stdarg.o stdio.o format.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_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_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 \ 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/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/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/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 \ 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 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 base64.o : std/base64.d
$(DMD) -c $(DFLAGS) 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 compiler.o : std/compiler.d
$(DMD) -c $(DFLAGS) std/compiler.d $(DMD) -c $(DFLAGS) std/compiler.d

755
std/boxer.d Normal file
View 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)));
}

View file

@ -1387,7 +1387,7 @@ class BufferedStream : Stream {
throw new WriteException("Unable to write to stream"); throw new WriteException("Unable to write to stream");
} }
} }
long diff = bufferCurPos-bufferSourcePos; long diff = cast(long)bufferCurPos-bufferSourcePos;
if (diff != 0 && seekable) { if (diff != 0 && seekable) {
// move actual file pointer to current position // move actual file pointer to current position
streamPos = s.seek(diff, SeekPos.Current); streamPos = s.seek(diff, SeekPos.Current);
@ -1417,7 +1417,7 @@ class BufferedStream : Stream {
// returns size of stream // returns size of stream
ulong size() { ulong size() {
flush(); if (bufferDirty) flush();
return s.size(); return s.size();
} }
@ -1785,12 +1785,17 @@ class BufferedFile: BufferedStream {
assert(file.position() == 18 + 13 + 4); assert(file.position() == 18 + 13 + 4);
// we must be at the end of file // we must be at the end of file
assert(file.eof()); assert(file.eof());
long oldsize = file.size();
file.close(); file.close();
// no operations are allowed when file is closed // no operations are allowed when file is closed
assert(!file.readable && !file.writeable && !file.seekable); assert(!file.readable && !file.writeable && !file.seekable);
file.open("stream.$$$"); file.open("stream.$$$");
// should be ok to read // should be ok to read
assert(file.readable); 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:")); assert(!std.string.cmp(file.readLine(), "Testing stream.d:"));
// jump over "Hello, " // jump over "Hello, "
file.seek(7, SeekPos.Current); file.seek(7, SeekPos.Current);

View file

@ -1374,6 +1374,7 @@ unittest
/************************************** /**************************************
* Split s[] into an array of lines, * Split s[] into an array of lines,
* using CR, LF, or CR-LF as the delimiter. * using CR, LF, or CR-LF as the delimiter.
* The delimiter is not included in the line.
*/ */
char[][] splitlines(char[] s) char[][] splitlines(char[] s)

View file

@ -13,13 +13,11 @@ class TypeInfo_v : TypeInfo
int equals(void *p1, void *p2) int equals(void *p1, void *p2)
{ {
assert(0);
return *cast(byte *)p1 == *cast(byte *)p2; return *cast(byte *)p1 == *cast(byte *)p2;
} }
int compare(void *p1, void *p2) int compare(void *p1, void *p2)
{ {
assert(0);
return *cast(byte *)p1 - *cast(byte *)p2; return *cast(byte *)p1 - *cast(byte *)p2;
} }
@ -32,7 +30,6 @@ class TypeInfo_v : TypeInfo
{ {
byte t; byte t;
assert(0);
t = *cast(byte *)p1; t = *cast(byte *)p1;
*cast(byte *)p1 = *cast(byte *)p2; *cast(byte *)p1 = *cast(byte *)p2;
*cast(byte *)p2 = t; *cast(byte *)p2 = t;

View file

@ -44,6 +44,7 @@ import std.zlib;
import std.md5; import std.md5;
import std.stdio; import std.stdio;
import std.conv; import std.conv;
import std.boxer;
int main(char[][] args) int main(char[][] args)
{ {
@ -76,6 +77,7 @@ printf("test2\n");
writefln("hello world!"); // std.format writefln("hello world!"); // std.format
Box abox;
{ {
creal c = 3.0 + 4.0i; creal c = 3.0 + 4.0i;
c = sqrt(c); c = sqrt(c);

View file

@ -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 \ Czlib.obj Dzlib.obj zip.obj process.obj registry.obj recls.obj \
socket.obj socketstream.obj loader.obj stdarg.obj format.obj stdio.obj \ socket.obj socketstream.obj loader.obj stdarg.obj format.obj stdio.obj \
perf.obj openrj.obj uni.obj winsock.obj oldsyserror.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_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_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 \ 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\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\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\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 \ 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 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 base64.obj : std\base64.d
$(DMD) -c $(DFLAGS) -inline 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 compiler.obj : std\compiler.d
$(DMD) -c $(DFLAGS) std\compiler.d $(DMD) -c $(DFLAGS) std\compiler.d