diff --git a/internal/aaA.d b/internal/aaA.d index f96a7e3b2..5c3b3cf56 100644 --- a/internal/aaA.d +++ b/internal/aaA.d @@ -42,6 +42,13 @@ static uint[] prime_list = [ 1610612741UL, 4294967291UL ]; +/* This is the type of the return value for dynamic arrays. + * It should be a type that is returned in registers. + * Although DMD will return types of Array in registers, + * gcc will not, so we instead use a 'long'. + */ +alias long ArrayRet_t; + struct Array { size_t length; @@ -77,7 +84,7 @@ struct AA { // This is here only to retain binary compatibility with the // old way we did AA's. Should eventually be removed. - int reserved; + //int reserved; } } @@ -451,7 +458,7 @@ void _aaDel(AA aa, TypeInfo keyti, ...) * Produce array of values from aa. */ -long _aaValues(AA aa, size_t keysize, size_t valuesize) +ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize) in { assert(keysize == aligntsize(keysize)); @@ -492,7 +499,7 @@ long _aaValues(AA aa, size_t keysize, size_t valuesize) } assert(resi == a.length); } - return *cast(long*)(&a); + return *cast(ArrayRet_t*)(&a); } @@ -500,7 +507,7 @@ long _aaValues(AA aa, size_t keysize, size_t valuesize) * Rehash an array. */ -long _aaRehash(AA* paa, TypeInfo keyti) +void* _aaRehash(AA* paa, TypeInfo keyti) in { //_aaInvAh(paa); @@ -587,7 +594,7 @@ long _aaRehash(AA* paa, TypeInfo keyti) *paa.a = newb; } - return *cast(long*)paa; + return (*paa).a; } @@ -595,7 +602,7 @@ long _aaRehash(AA* paa, TypeInfo keyti) * Produce array of N byte keys from aa. */ -long _aaKeys(AA aa, size_t keysize) +ArrayRet_t _aaKeys(AA aa, size_t keysize) { byte[] res; size_t resi; @@ -632,7 +639,7 @@ long _aaKeys(AA aa, size_t keysize) Array a; a.length = len; a.ptr = res; - return *cast(long*)(&a); + return *cast(ArrayRet_t*)(&a); } diff --git a/internal/cmath2.d b/internal/cmath2.d index bdeea6fe6..6534d92d2 100644 --- a/internal/cmath2.d +++ b/internal/cmath2.d @@ -107,7 +107,7 @@ void _Cmul() * ST0 imaginary part */ -creal _Cdiv() +void _Cdiv() { real x_re, x_im; real y_re, y_im; @@ -166,8 +166,13 @@ creal _Cdiv() q_im = 0.0 * (x_im * y_re - x_re * y_im); } } -+/ return q_re + q_im * 1.0i; ++/ + asm + { + fld q_re; + fld q_im; + } } /**************************** diff --git a/internal/deh.c b/internal/deh.c index 547e17fc5..8a1e951ce 100644 --- a/internal/deh.c +++ b/internal/deh.c @@ -33,7 +33,9 @@ extern DWORD _except_list; #include "mars.h" -extern ClassInfo _Class_9Exception; +extern ClassInfo D9Exception7__ClassZ; + +#define _Class_9Exception D9Exception7__ClassZ typedef int (__pascal *fp_t)(); // function pointer in ambient memory model @@ -411,7 +413,9 @@ void _d_monitor_epilog(void *x, void *y, Object *h) #include "mars.h" -extern ClassInfo _Class_9Exception; +extern ClassInfo D9Exception7__ClassZ; + +#define _Class_9Exception D9Exception7__ClassZ typedef int (*fp_t)(); // function pointer in ambient memory model diff --git a/internal/object.d b/internal/object.d index 6701033f7..b428320e8 100644 --- a/internal/object.d +++ b/internal/object.d @@ -558,7 +558,7 @@ class TypeInfo_AssociativeArray : TypeInfo size_t tsize() { - return (void[]).sizeof; + return (char[int]).sizeof; } TypeInfo next; diff --git a/linux.mak b/linux.mak index bc14712a5..e48468cca 100644 --- a/linux.mak +++ b/linux.mak @@ -57,7 +57,7 @@ OBJS = asserterror.o deh2.o switch.o complex.o gcstats.o \ process.o syserror.o \ socket.o socketstream.o stdarg.o stdio.o format.o \ perf.o openrj.o uni.o trace.o boxer.o \ - demangle.o cover.o bitarray.o aApplyR.o \ + demangle.o cover.o bitarray.o bind.o aApplyR.o \ signals.o cpuid.o traits.o typetuple.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 \ @@ -94,7 +94,7 @@ SRC_STD= std/zlib.d std/zip.d std/stdint.d std/conv.d std/utf.d std/uri.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/boxer.d std/cstream.d std/demangle.d std/cover.d std/bitarray.d \ - std/signals.d std/cpuid.d std/typetuple.d std/traits.d + std/signals.d std/cpuid.d std/typetuple.d std/traits.d std/bind.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/fenv.d std/c/string.d \ @@ -307,6 +307,9 @@ asserterror.o : std/asserterror.d base64.o : std/base64.d $(DMD) -c $(DFLAGS) std/base64.d +bind.o : std/bind.d + $(DMD) -c $(DFLAGS) std/bind.d + bitarray.o : std/bitarray.d $(DMD) -c $(DFLAGS) std/bitarray.d @@ -601,4 +604,4 @@ zip : $(ALLSRCS) linux.mak win32.mak phoboslicense.txt zip phobos $(ALLSRCS) linux.mak win32.mak phoboslicense.txt clean: - $(RM) $(OBJS) unittest unittest.o + $(RM) libphobos.a $(OBJS) unittest unittest.o diff --git a/phobos.d b/phobos.d index a56b7382c..a690f3643 100644 --- a/phobos.d +++ b/phobos.d @@ -124,6 +124,12 @@ D language compiler. Also, check out the
std.base64
Encode/decode base64 format. +
std.bind +
Bind function arguments. + +
std.bitarray +
Arrays of bits. +
std.boxer
Box/unbox types. diff --git a/std.ddoc b/std.ddoc index a8ba23388..682b083bf 100644 --- a/std.ddoc +++ b/std.ddoc @@ -111,6 +111,7 @@ NAVIGATION_PHOBOS=

std

$(UL $(LI std.base64) + $(LI std.bind) $(LI std.bitarray) $(LI std.boxer) $(LI std.compiler) diff --git a/std/bind.d b/std/bind.d new file mode 100644 index 000000000..d77c9f325 --- /dev/null +++ b/std/bind.d @@ -0,0 +1,1053 @@ +/** + * Bind function arguments to functions. + * + * References: + * $(LINK2 http://www.boost.org/libs/bind/bind.html, boost::bind) + * Authors: Tomasz Stachowiak + * Date: November 28, 2006 + * Macros: + * WIKI = Phobos/StdBind + * Copyright: + * Public Domain + */ +module std.bind; + + +import std.string : stdFormat = format; +import std.traits; +import std.typetuple; + + + + + +struct DynArg(int i) { + static assert (i >= 0); + + alias i argNr; +} + + +/** + When passed to the 'bind' function, they will mark dynamic params - ones that aren't statically bound + In boost, they're called __1, __2, __3, etc.. here __0, __1, __2, ... +*/ +const DynArg!(0) _0; +const DynArg!(1) _1; /// ditto +const DynArg!(2) _2; /// ditto +const DynArg!(3) _3; /// ditto +const DynArg!(4) _4; /// ditto +const DynArg!(5) _5; /// ditto +const DynArg!(6) _6; /// ditto +const DynArg!(7) _7; /// ditto +const DynArg!(8) _8; /// ditto +const DynArg!(9) _9; /// ditto + + + +/* + Detect if a given type is a DynArg of any index +*/ +template isDynArg(T) { + static if (is(typeof(T.argNr))) { // must have the argNr field + static if(is(T : DynArg!(T.argNr))) { // now check the exact type + static const bool isDynArg = true; + } else static const bool isDynArg = false; + } else static const bool isDynArg = false; +} + + +/* + Detect if a given type is a DynArg of the specified index +*/ +template isDynArg(T, int i) { + static const bool isDynArg = is(T : DynArg!(i)); +} + + +/* + Converts a static array type to a dynamic array type +*/ +template DynamicArrayType(T) { + alias typeof(T[0])[] DynamicArrayType; +} + + +/* + Assigns one entity to another. As static arrays don't like normal assignment, slice assignment is used for them. + + Params: + a = destination + b = source +*/ +template _assign(T) { + static if (isStaticArray!(T)) { + void _assign(DynamicArrayType!(T) a, DynamicArrayType!(T) b) { + a[] = b[]; + } + } else { + void _assign(inout T a, inout T b) { + a = b; + } + } +} + + +/* + Assigns and potentially converts one entity to another + + Normally, only implicit conversion is used, but when both operands are numeric types, an explicit cast is performed on them. + + Params: + T = destination type + a = destination + Y = source type + b = source + copyStaticArrays = when a static array is assigned to a dynamic one, it sometimes has to be .dup'ed as the storage may exist in volatile locations +*/ +template _assign(T, Y, bool copyStaticArrays = true) { + static if (isStaticArray!(T)) { + + // if the destination is a static array, copy each element from the source to the destination by a foreach + void _assign(DynamicArrayType!(T) a, DynamicArrayType!(Y) b) { + foreach (i, x; b) { + _assign!(typeof(a[i]), typeof(x))(a[i], x); + } + } + } else static if (!isStaticArray!(T) && isStaticArray!(Y)) { + + // the destination is a dynamic array and the source is a static array. this sometimes needs a .dup + void _assign(inout T a, DynamicArrayType!(Y) b) { + static if (copyStaticArrays) { + a = b.dup; + } else { + a = b; + } + } + } else { + + // none of the items is a static array + void _assign(inout T a, inout Y b) { + static if (IndexOf!(T, NumericTypes.type) != -1 && IndexOf!(Y, NumericTypes.type) != -1) { + a = cast(T)b; + } else { + a = b; + } + } + } +} + + + +/** + A simple tuple struct with some basic operations +*/ +struct Tuple(T ...) { + alias Tuple meta; + const bool expressionTuple = isExpressionTuple!(T); + + static if (!expressionTuple) { + alias T type; // a built-in tuple + T value; // a built-in tuple instance + } else { + alias T value; + } + + + const int length = value.length; + + + /** + Statically yields a tuple type with an extra element added at its end + */ + template appendT(X) { + alias .Tuple!(T, X) appendT; + } + + + /** + Yields a tuple with an extra element added at its end + */ + appendT!(X) append(X)(X x) { + appendT!(X) res; + foreach (i, y; value) { + _assign!(typeof(y))(res.value[i], y); + } + _assign!(typeof(x))(res.value[$-1], x); + return res; + } + + + /** + Statically yields a tuple type with an extra element added at its beginning + */ + template prependT(X) { + alias .Tuple!(X, T) prependT; + } + + + /** + Yields a tuple with an extra element added at its beginning + */ + prependT!(X) prepend(X)(X x) { + prependT!(X) res; + foreach (i, y; value) { + _assign!(typeof(y))(res.value[i+1], y); + } + _assign!(typeof(x))(res.value[0], x); + return res; + } + + + /** + Statically concatenates this tuple type with another tuple type + */ + template concatT(T ...) { + static if (expressionTuple) { + alias .Tuple!(value, T) concatT; + } else { + alias .Tuple!(type, T) concatT; + } + } + + + char[] toString() { + char[] res = "(" ~ stdFormat(value[0]); + foreach (x; value[1..$]) { + res ~= stdFormat(", ", x); + } + return res ~ ")"; + } +} + + +/** + An empty tuple struct +*/ +struct Tuple() { + alias Tuple meta; + + template EmptyTuple_(T ...) { + alias T EmptyTuple_; + } + + + alias EmptyTuple_!() type; /// an empty built-in tuple + alias EmptyTuple_!() value; /// an empty built-in tuple + + const bool expressionTuple = false; + const int length = 0; + + + template appendT(X) { + alias .Tuple!(X) appendT; + } + alias appendT prependT; + + + appendT!(X) append(X)(X x) { + appendT!(X) res; + foreach (i, y; value) { + _assign!(typeof(y))(res.value[i], y); + } + return res; + } + alias append prepend; + + + // T - other tuple + template concatT(T ...) { + alias .Tuple!(T) concatT; + } + + + char[] toString() { + return "()"; + } +} + + +/** + Dynamically create a tuple from the given items +*/ +Tuple!(T) tuple(T ...)(T t) { + Tuple!(T) res; + foreach (i, x; t) { + _assign!(typeof(x))(res.value[i], x); + } + return res; +} + + +/** + Checks whether a given type is the Tuple struct of any length +*/ +template isTypeTuple(T) { + static if (is(T.type)) { + static if (is(T == Tuple!(T.type))) { + const bool isTypeTuple = true; + } else const bool isTypeTuple = false; + } else const bool isTypeTuple = false; +} + +static assert(isTypeTuple!(Tuple!(int))); +static assert(isTypeTuple!(Tuple!(float, char))); +static assert(isTypeTuple!(Tuple!(double, float, int, char[]))); +static assert(isTypeTuple!(Tuple!(Object, creal, long))); +static assert(!isTypeTuple!(Object)); +static assert(!isTypeTuple!(int)); + + + + +template minNumArgs_impl(alias fn, fnT) { + alias ParameterTypeTuple!(fnT) Params; + Params params = void; + + template loop(int i = 0) { + static assert (i <= Params.length); + + static if (is(typeof(fn(params[0..i])))) { + const int res = i; + } else { + alias loop!(i+1).res res; + } + } + + alias loop!().res res; +} +/** + Finds the minimal number of arguments a given function needs to be provided +*/ +template minNumArgs(alias fn, fnT = typeof(&fn)) { + const int minNumArgs = minNumArgs_impl!(fn, fnT).res; +} + + +// mixed into BoundFunc struct/class +template MBoundFunc() { + // meta + alias FAlias_ FAlias; + alias FT FuncType; + alias AllBoundArgs_ AllBoundArgs; // all arguments given to bind() or bindAlias() + + static if (!is(typeof(FAlias) == EmptySlot)) { + alias Tuple!(ParameterTypeTuple!(FT)) RealFuncParams; // the parameters of the bound function + alias FuncReferenceParamsAsPointers!(FAlias) FuncParams; // references converted to pointers + } else { + alias Tuple!(ParameterTypeTuple!(FT)) FuncParams; // the parameters of the bound function + } + + alias ReturnType!(FT) RetType; // the return type of the bound function + alias ExtractedBoundArgs!(AllBoundArgs.type) BoundArgs; // 'saved' arguments. this includes nested/composed functions + + + // if bindAlias was used, we can detect default arguments and only demand the non-default arguments to be specified + static if (!is(typeof(FAlias) == EmptySlot)) { + const int minFuncArgs = minNumArgs!(FAlias); + + alias ParamsPassMethodTuple!(FAlias) ParamPassingMethods; // find out whether the function expects parameters by value or reference + } else { + const int minFuncArgs = FuncParams.length; + } + + // the parameters that our wrapper function must get + alias getDynArgTypes!(FuncParams, AllBoundArgs, minFuncArgs).res.type DynParams; + + // data + FuncType fp; + BoundArgs boundArgs; + + // yields the number of bound-function parameters that are covered by the binding. takes tuple expansion into account + template numFuncArgsReallyBound(int argI = 0, int fargI = 0, int bargI = 0) { + + // walk though all of AllBoundArgs + static if (argI < AllBoundArgs.length) { + + // the argI-th arg is a composed/nested function + static if (isBoundFunc!(AllBoundArgs.type[argI])) { + alias DerefFunc!(AllBoundArgs.type[argI]).RetType FuncRetType; + const int argLen = getArgLen!(FuncParams.type[fargI], FuncRetType); + const int bargInc = 1; + } + + // the argI-th arg is a dynamic argument whose value we will get in the call to func() + else static if (isDynArg!(AllBoundArgs.type[argI])) { + const int argLen = getArgLen!(FuncParams.type[fargI], DynParams[AllBoundArgs.type[argI].argNr]); + const int bargInc = 0; + } + + // the argI-th arg is a statically bound argument + else { + const int argLen = getArgLen!(FuncParams.type[fargI], BoundArgs.type[bargI]); + const int bargInc = 1; + } + + // iterate + const int res = numFuncArgsReallyBound!(argI+1, fargI+argLen, bargI+bargInc).res; + } else { + // last iteration + + // the number of bound args is the number of arguments we've detected in this template loop + const int res = fargI; + + // make sure we'll copy all args the function is going to need + static assert (res >= minFuncArgs); + } + } + + const int numSpecifiedParams = numFuncArgsReallyBound!().res; + + // it's a tuple type whose instance will be applied to the bound function + alias Tuple!(FuncParams.type[0 .. numSpecifiedParams]) SpecifiedParams; + + + // argI = indexes AllBoundArgs + // fargI = indexes funcArgs + // bargI = indexes boundArgs + void copyArgs(int argI = 0, int fargI = 0, int bargI = 0)(inout SpecifiedParams funcArgs, DynParams dynArgs) { + static if (argI < AllBoundArgs.length) { + + // the argI-th arg is a composed/nested function + static if (isBoundFunc!(AllBoundArgs.type[argI])) { + alias DerefFunc!(AllBoundArgs.type[argI]).RetType FuncRetType; + alias DerefFunc!(AllBoundArgs.type[argI]).DynParams FuncDynParams; + + // if FuncDynParams contains an empty slot, e.g. as in the case bind(&f, bind(&g, _1), _0) + // then we cannot just apply the dynArgs tuple to the nested/composed function because it will have EmptySlot params + // while our dynArgs tuple will contain ordinary types + static if (ContainsEmptySlotType!(FuncDynParams)) { + + FuncDynParams funcParams; // we'll fill it with values in a bit + + foreach (i, dummy_; dynArgs) { + static if (!is(typeof(FuncDynParams[i] == EmptySlot))) { + + // 3rd param is false because there is no need to .dup static arrays just for the function below this foreach + // the storage exists in the whole copyArgs function + // dynArgs[i] is used instead of dummy_ so that loop-local data isn't referenced in any dynamic arrays after the loop + _assign!(typeof(funcParams[i]), typeof(dummy_), false)(funcParams[i], dynArgs[i]); + } + } + + FuncRetType funcRet = boundArgs.value[bargI].func(funcParams); + } else { + FuncRetType funcRet = boundArgs.value[bargI].func(dynArgs[0..FuncDynParams.length]); // only give it as many dynParams as it needs + } + + // we'll take data from the returned value + auto srcItem = &funcRet; + + const int bargInc = 1; // nested/composed functions belong to the boundArgs tuple + const bool dupStaticArrays = true; // because the function's return value is stored locally + } + + // the argI-th arg is a dynamic argument whose value we will get in the call to func() + else static if (isDynArg!(AllBoundArgs.type[argI])) { + + // we'll take data from dynArgs + auto srcItem = &dynArgs[AllBoundArgs.type[argI].argNr]; + + const int bargInc = 0; // dynamic args don't belond to the boundArgs tuple + const bool dupStaticArrays = true; // because we get dynArgs on stack + } + + // the argI-th arg is a statically bound argument + else { + + // we'll take data directly from boundArgs + auto srcItem = &boundArgs.value[bargI]; + + const int bargInc = 1; // statically bound args belong to the boundArgs tuple + const bool dupStaticArrays = false; // because the storage exists in boundArgs + } + + // the number of bound-function parameters this argument will cover after tuple expansion + const int argLen = getArgLen!(funcArgs.type[fargI], typeof(*srcItem)); + + static if (isTypeTuple!(typeof(*srcItem)) && !isTypeTuple!(funcArgs.type[fargI])) { + foreach (i, x; srcItem.value) { + _assign!(funcArgs.type[fargI + i], typeof(x), dupStaticArrays)(funcArgs.value[fargI + i], x); + } + } else { + static assert (1 == argLen); + _assign!(funcArgs.type[fargI], typeof(*srcItem), dupStaticArrays)(funcArgs.value[fargI], *srcItem); + } + + // because we might've just expended a tuple, this may be larger than one + static assert (argLen >= 1); + + // we could've just used a dynamic arg (0) or a statically bound arg(1) + static assert (bargInc == 0 || bargInc == 1); + + + return copyArgs!(argI+1, fargI+argLen, bargI+bargInc)(funcArgs, dynArgs); + } else { + // last iteration + + // make sure we've copied all args the function will need + static assert (fargI >= minFuncArgs); + } + } + + + static if (SpecifiedParams.length > 0) { + /// The final wrapped function + RetType func(DynParams dynArgs) { + SpecifiedParams funcArgs; + copyArgs!()(funcArgs, dynArgs); + + // if the function expects any parameters passed by reference, we'll have to use the ptrApply template + // and convert pointers back to references by hand + static if (!is(typeof(FAlias) == EmptySlot) && IndexOf!(PassByRef, ParamPassingMethods.type) != -1) { + + // function parameter type pointers (int, float*, inout char) -> (int*, float*, char*) + PointerTuple!(Tuple!(RealFuncParams.type[0 .. SpecifiedParams.length])) ptrs; + + // initialize the 'ptrs' tuple instance + foreach (i, dummy_; funcArgs.value) { + static if (is(ParamPassingMethods.type[i] == PassByRef)) { + + version (BindNoNullCheck) {} + else { + assert (funcArgs.value[i], "references cannot be null"); + } + + ptrs.value[i] = funcArgs.value[i]; + } else { + ptrs.value[i] = &funcArgs.value[i]; + } + } + + // and call the function :) + ptrApply!(RetType, FuncType, ptrs.type)(fp, ptrs.value); + } else { + + // ordinary call-by-tuple + return fp(funcArgs.value); + } + } + } else { + /// The final wrapped function + RetType func() { + return fp(); + } + } + + /// The final wrapped function + alias func call; + + + /// The final wrapped function + alias func opCall; + + + /** + The type of the delegate that may be returned from this object + */ + template PtrType() { + alias typeof(&(new BoundFunc).call) PtrType; + } + + /** + Get a delegate. Equivalent to getting it thru &foo.call + */ + PtrType!() ptr() { + return &this.func; + } +} + + +version (BindUseStruct) { + template DerefFunc(T) { + alias typeof(*T) DerefFunc; + } + + /** + A context for bound/curried functions + */ + struct BoundFunc(FT, alias FAlias_, AllBoundArgs_) { + mixin MBoundFunc; + } +} else { + template DerefFunc(T) { + alias T DerefFunc; + } + + /** + A context for bound/curried functions + */ + class BoundFunc(FT, alias FAlias_, AllBoundArgs_) { + mixin MBoundFunc; + } +} + + +/** + bind() can curry or "bind" arguments of a function, producing a different function which requires less parameters, + or a different order of parameters. It also allows function composition. + + The syntax of a bind() call is: + + bind(function or delegate pointer { , argument }); + + argument can be one of: + + + The result is a function object, which can be called using call(), func() or opCall(). + There also exists a convenience function, ptr() which returns a delegate to call/func/opCall + + The resulting delegate accepts exactly as many parameters as many distinct dynamic arguments were used. +--- +- bind(&foo, _0, _1) // will yield a delegate accepting two parameters +- bind(&foo, _1, _0) // will yield a delegate accepting two parameters +- bind(&bar, _0, _1, _2, _0) // will yield a delegate accepting three parameters +--- + +
+
+ The types of dynamic parameters are extracted from the bound function itself and when necessary, type negotiation + is performed. For example, binding a function +--- +void foo(int a, long b) + +// with: +bind(&foo, _0, _0) +--- + will result in a delegate accepting a single, optimal parameter type. The best type is computed + using std.typetuple.DerivedToFront, so in case of an int and a long, long will be selected. Generally, bind will try to find + a type that can be implicitly converted to all the other types a given dynamic parameter uses. + Note: in case of numeric types, an explicit, but transparent (to the user) cast will be performed + +
+ Function composition works intuitively: +--- +bind(&f1, bind(&f2, _0)) +--- + + which will yield a delegate, that takes the argument, calls f2, then uses the return value of f2 to call f1. Mathematically + speaking, it will yield a function composition: +--- +f1(f2(_0)) +--- + + When one function is composed multiple times, it will be called multiple times - Bind does no lazy evaluation, so +--- +bind(&f3, bind(&f4, _0), bind(&f4, _0)) +--- + will produce a delegate, which, upon calling, will invoke f4 two times to evaluate the arguments for f3 and then call f3 + + + One another feature that bind() supports is automatic tuple expansion. It means that having functions: +--- +void foo(int a, int b) +Tuple!(int, int) bar() +--- + + Allows them to be bound by writing: +--- +bind(&foo, bind(&bar)) +// or +bind(&foo, tuple(23, 45)) +--- +*/ +typeof(new BoundFunc!(FT, NullAlias, Tuple!(ArgList))) bind(FT, ArgList...)(FT fp, ArgList args) { + auto res = new DerefFunc!(ReturnType!(bind)); + res.fp = fp; + extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); + return res; +} + + +/** + bindAlias() is similar to bind(), but it's more powerful. Use bindAlias() rather than bind() where possible.
+ + + The syntax is: + + bindAlias!(Function)(argument, argument, argument, argument, ...); + + bindAlias takes advantage of using aliases directly, thus being able to extract default values from functions and not forcing the user + to bind them. It doesn't, however mean that the resulting delegate can be called, omitting some of its parameters. It only means that these + arguments that have default values in the function provided to bindAlias don't have to be bound explicitly. + + Additionally, bindAlias takes care of functions with out/inout parameters, by converting them to pointers internally. A function like: +--- +void foo(inout a) +--- + can be bound using: +--- +int x; +bindAlias!(foo)(&x); +--- + + Note: there is no bind-time check for reference nullness, there is however a call-time check on all references which can be disabled + by using version=BindNoNullCheck or compiling in release mode. +*/ +template bindAlias(alias FT) { + typeof(new BoundFunc!(typeof(&FT), FT, Tuple!(ArgList))) bindAlias(ArgList...)(ArgList args) { + auto res = new DerefFunc!(ReturnType!(bindAlias)); + res.fp = &FT; + extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); + return res; + } +} + + + + + +/* + Tells whether the specified type is a bound function +*/ +template isBoundFunc(T) { + static if (is(DerefFunc!(T).FuncType)) { + static if (is(DerefFunc!(T).BoundArgs)) { + static if (is(typeof(DerefFunc!(T).FAlias))) { + static if (is(DerefFunc!(T) : BoundFunc!(DerefFunc!(T).FuncType, DerefFunc!(T).FAlias, DerefFunc!(T).AllBoundArgs))) { + static const bool isBoundFunc = true; + } else static const bool isBoundFunc = false; + } else static const bool isBoundFunc = false; + } else static const bool isBoundFunc = false; + } else static const bool isBoundFunc = false; +} + + +// all numeric types as of dmd.175 +alias Tuple!(byte, ubyte, short, ushort, int, uint, long, ulong, /+cent, ucent, +/float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal) NumericTypes; + + + +/* + Gather all types that a given (i-th) dynamic arg uses. + The types will be inserted into a tuple +*/ +template dynArgTypes(int i, FuncParams, BoundArgs, int minParamsLeft) { + + // performs slicing on the tuple ... tuple[i .. length] + template sliceOffTuple(T, int i) { + alias Tuple!(T.type[i..length]) res; + } + + // prepends a T to the resulting tuple + // SkipType - the type in BoundArgs that we're just processing + template prependType(T, SkipType) { + static if (isTypeTuple!(SkipType) && !isTypeTuple!(FuncParams.type[0])) { + // perform tuple decomposition + // e.g. if a function being bound is accepting (int, int) and the current type is a Tuple!(int, int), + // then skip just one tuple in the bound args and the length of the tuple in func args + // - skips two ints and one tuple in the example + alias dynArgTypes!( + i, + sliceOffTuple!(FuncParams, SkipType.length).res, + Tuple!(BoundArgs.type[1..$]), + minParamsLeft - SkipType.length + ).res tmp; + + } else { + // just advance by one type + alias dynArgTypes!( + i, + sliceOffTuple!(FuncParams, 1).res, + Tuple!(BoundArgs.type[1..$]), + minParamsLeft-1 + ).res tmp; + } + + static if (is(T == void)) { // void means that we aren't adding anything + alias tmp res; + } else { + alias tmp.prependT!(T) res; + } + } + + // iteration end detector + static if (is(BoundArgs == Tuple!())) { + static assert (minParamsLeft <= 0, "there are still unbound function parameters"); + alias Tuple!() res; + } + else { + + // w00t, detected a regular dynamic arg + static if (isDynArg!(BoundArgs.type[0], i)) { + alias prependType!(FuncParams.type[0], BoundArgs.type[0]).res res; + } + + // the arg is a bound function, extract info from it. we will be evaluating it later + else static if (isBoundFunc!(BoundArgs.type[0])) { + alias DerefFunc!(BoundArgs.type[0]) BoundFunc; // the bound function is a struct pointer, we have to derefernce its type + + // does that function even have any dynamic params ? + static if (BoundFunc.DynParams.length > i) { + alias prependType!(BoundFunc.DynParams[i], BoundFunc.RetType).res res; + } + // it doesn't + else { + alias prependType!(void, BoundFunc.RetType).res res; + } + } + + // a static arg, just skip it since we want to find all types a given DynArg uses. static args <> dyn args + else alias prependType!(void, BoundArgs.type[0]).res res; + } +} + + +// just a simple util +private template maxInt(int a, int b) { + static if (a > b) static const int maxInt = a; + else static const int maxInt = b; +} + + +/* + Given a list of BoundArgs, it returns the nuber of args that should be specified dynamically +*/ +template numDynArgs(BoundArgs) { + static if (BoundArgs.length == 0) { + // received an EmptyTuple + static const int res = 0; + } else { + // ordinary dynamic arg + static if (isDynArg!(BoundArgs.type[0])) { + static const int res = maxInt!(BoundArgs.type[0].argNr+1, numDynArgs!(Tuple!(BoundArgs.type[1..$])).res); + } + + // count the args in nested / composed functions + else static if (isBoundFunc!(BoundArgs.type[0])) { + static const int res = maxInt!(DerefFunc!(BoundArgs.type[0]).DynParams.length, numDynArgs!(Tuple!(BoundArgs.type[1..$])).res); + } + + // statically bound arg, skip it + else { + static const int res = numDynArgs!(Tuple!(BoundArgs.type[1..$])).res; + } + } +} + + +/* + Used internally to mark a parameter which is a dummy placeholder + E.g. when using bind(&f, bind(&g, _1), _0), then the inner bound function will use an EmptySlot for its 0-th parameter +*/ +struct EmptySlot { + char[] toString( ) { + return "_"; + } +} + + +/* + Get a tuple of all dynamic args a function binding will need + take nested/composed functions as well as tuple decomposition into account +*/ +template getDynArgTypes(FuncParams, BoundArgs, int minFuncArgs) { + template loop(int i) { + static if (i < numDynArgs!(BoundArgs).res) { + alias dynArgTypes!(i, FuncParams, BoundArgs, minFuncArgs).res.type dirtyArgTypeList; + + // 'clean' the type list, erasing all NoTypes from it that could've been added there from composed functions + // if the arg is not used, we'll mark it as NoType anyway, but for now, we only want 'real' types so the most derived one can be found + alias Tuple!(EraseAll!(EmptySlot, dirtyArgTypeList)) argTypeList; + + + // make sure the arg is used + static if(!is(argTypeList == Tuple!())) { + alias DerivedToFront!(argTypeList.type)[0] argType; + } else { + //static assert(false, i); + alias EmptySlot argType; + } + + alias loop!(i+1).res.meta.prependT!(argType) res; + } else { + alias Tuple!() res; + } + } + + alias loop!(0).res res; +} + + +/* + Given a tuple that bind() was called with, it will detect which types need to be stored in a BoundFunc object +*/ +template ExtractedBoundArgs(BoundArgs ...) { + static if (BoundArgs.length == 0) { + alias Tuple!() ExtractedBoundArgs; + } + + // we'll store all non-dynamic arguments... + else static if (!isDynArg!(BoundArgs[0])) { + alias ExtractedBoundArgs!(BoundArgs[1..$]).meta.prependT!(BoundArgs[0]) ExtractedBoundArgs; + } + + // ... and we're going to leave the dynamic ones for later + else { + alias ExtractedBoundArgs!(BoundArgs[1..$]) ExtractedBoundArgs; + } +} + + +/* + Given a tuple that bind() was called with, it will copy all data that a BoundFunc object will store into an ExtractedBoundArgs tuple +*/ +void extractBoundArgs(int dst, int src, BoundArgs ...)(inout ExtractedBoundArgs!(BoundArgs) result, BoundArgs boundArgs) { + static if (dst < result.length) { + // again, we only want non-dynamic arguments here + static if (!isDynArg!(BoundArgs[src])) { + _assign!(typeof(result.value[dst]), typeof(boundArgs[src]))(result.value[dst], boundArgs[src]); + return extractBoundArgs!(dst+1, src+1, BoundArgs)(result, boundArgs); + } + + // the dynamic ones will be specified at the time BoundFunc.call() is invoked + else { + return extractBoundArgs!(dst, src+1, BoundArgs)(result, boundArgs); + } + } +} + + +/* + Number of args in the bound function that this Src arg will cover +*/ +template getArgLen(Dst, Src) { + // if the arg is a tuple and the target isn't one, it will be expanded/decomposed to the tuple's length + static if (isTypeTuple!(Src) && !isTypeTuple!(Dst)) { + static const int getArgLen = Src.length; + } + + // plain arg - it will use 1:1 mapping of functioni params to bound params + else { + static const int getArgLen = 1; + } +} + + +/* + Tell whether a parameter type tuple contains an EmptySlot struct +*/ +template ContainsEmptySlotType(ParamList ...) { + const bool ContainsEmptySlotType = -1 != IndexOf!(EmptySlot, ParamList); +} + + +// just something to be default in bind(). bindAlias() will use real aliases. +const EmptySlot NullAlias; + + + + +struct PassByCopy {} +struct PassByRef {} + +template ParamsPassMethodTuple_impl(alias Func, int i = 0) { + alias Tuple!(ParameterTypeTuple!(typeof(&Func))) Params; + + static if (Params.length == i) { + alias Tuple!() res; + } else { + Params params = void; + const params.type[i] constParam; + + // if the function expects references, it won't like our const. + static if (is(typeof(Func(params.value[0..i], constParam, params.value[i+1..$])))) { + alias ParamsPassMethodTuple_impl!(Func, i+1).res.meta.prependT!(PassByCopy) res; + } else { + alias ParamsPassMethodTuple_impl!(Func, i+1).res.meta.prependT!(PassByRef) res; + } + } +} + +/* + Detect parameter passing methods: PassByCopy or PassByRef[erence] +*/ +template ParamsPassMethodTuple(alias Func) { + alias ParamsPassMethodTuple_impl!(Func).res ParamsPassMethodTuple; +} + + +template FuncReferenceParamsAsPointers_impl(alias Func) { + alias Tuple!(ParameterTypeTuple!(typeof(&Func))) Params; + alias ParamsPassMethodTuple!(Func) PassMethods; + + template loop(int i) { + static if (i == Params.length) { + alias Tuple!() res; + } else { + static if (is(PassMethods.type[i] == PassByRef)) { + alias Params.type[i]* type; + } else { + alias Params.type[i] type; + } + + alias loop!(i+1).res.meta.prependT!(type) res; + } + } + + alias loop!(0).res res; +} + +/* + Takes a function/delegate alias and converts its refence parameters to pointers. E.g. + + void function(int, inout char, float*) -> (int, char*, float*) +*/ +template FuncReferenceParamsAsPointers(alias Func) { + alias FuncReferenceParamsAsPointers_impl!(Func).res FuncReferenceParamsAsPointers; +} + + + +/* + Converts a tuple of types to a tuple containing pointer types of the original types +*/ +template PointerTuple(T) { + static if (T.length > 0) { + alias PointerTuple!(Tuple!(T.type[1..$])).meta.prependT!(T.type[0]*) PointerTuple; + } else { + alias Tuple!() PointerTuple; + } +} + + + +/* + Calls a function, dereferencing a pointer tuple for each argument +*/ +RetType ptrApply(RetType, FN, T ...)(FN fn, T t) { + static if (1 == T.length) { + return fn(*t[0]); + } + else static if (2 == T.length) { + return fn(*t[0], *t[1]); + } + else static if (3 == T.length) { + return fn(*t[0], *t[1], *t[2]); + } + else static if (4 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3]); + } + else static if (5 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4]); + } + else static if (6 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4], *t[5]); + } + else static if (7 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4], *t[5], *t[6]); + } + else static if (8 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4], *t[5], *t[6], *t[7]); + } + else static if (9 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4], *t[5], *t[6], *t[7], *t[8]); + } + else static if (10 == T.length) { + return fn(*t[0], *t[1], *t[2], *t[3], *t[4], *t[5], *t[6], *t[7], *t[8], *t[9]); + } +} diff --git a/std/c/linux/linux.d b/std/c/linux/linux.d index b08f8c0d5..3a16b105f 100644 --- a/std/c/linux/linux.d +++ b/std/c/linux/linux.d @@ -173,6 +173,10 @@ extern (C) tm* gmtime(__time_t*); tm* localtime(__time_t*); __time_t mktime(tm*); + char* asctime_r(tm* t, char* buf); + char* ctime_r(__time_t* timep, char* buf); + tm* gmtime_r(__time_t* timep, tm* result); + tm* localtime_r(__time_t* timep, tm* result); } /**************************************************************/ diff --git a/std/c/linux/socket.d b/std/c/linux/socket.d index b5aaa8519..ad31d0964 100644 --- a/std/c/linux/socket.d +++ b/std/c/linux/socket.d @@ -35,6 +35,8 @@ int setsockopt(int s, int level, int optname, void* optval, int optlen); uint inet_addr(char* cp); char* inet_ntoa(in_addr ina); hostent* gethostbyname(char* name); +int gethostbyname_r(char* name, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop); +int gethostbyname2_r(char* name, int af, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop); hostent* gethostbyaddr(void* addr, int len, int type); protoent* getprotobyname(char* name); protoent* getprotobynumber(int number); @@ -46,6 +48,7 @@ void freeaddrinfo(addrinfo* ai); int getnameinfo(sockaddr* sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags); + enum: int { AF_UNSPEC = 0, diff --git a/std/compiler.d b/std/compiler.d index eb5d6539d..2e9ae81ba 100644 --- a/std/compiler.d +++ b/std/compiler.d @@ -33,13 +33,13 @@ const * version_major.version_minor */ uint version_major = 0; - uint version_minor = 0; /// ditto + uint version_minor = 176; /// ditto /** * The version of the D Programming Language Specification * supported by the compiler. */ - uint D_major = 0; - uint D_minor = 134; + uint D_major = 1; + uint D_minor = 0; } diff --git a/std/math.d b/std/math.d index 69aaccf01..6b77bb3af 100644 --- a/std/math.d +++ b/std/math.d @@ -347,24 +347,24 @@ real atan(real x) { return std.c.math.atanl(x); } * Calculates the arc tangent of y / x, * returning a value ranging from -π/2 to π/2. * - * $(TABLE_SV - * x y atan(x, y) - * $(NAN) anything $(NAN) - * anything $(NAN) $(NAN) - * ±0.0 > 0.0 ±0.0 - * ±0.0 ±0.0 ±0.0 - * ±0.0 < 0.0 ±π - * ±0.0 -0.0 ±π - * > 0.0 ±0.0 π/2 - * < 0.0 ±0.0 π/2 - * > 0.0 ∞ ±0.0 - * ±∞ anything ±π/2 - * > 0.0 -∞ ±π - * ±∞ ∞ ±π/4 - * ±∞ -∞ ±3π/4 + * $(TABLE_SV + * y x atan(y, x) + * $(NAN) anything $(NAN) + * anything $(NAN) $(NAN) + * ±0.0 > 0.0 ±0.0 + * ±0.0 ±0.0 ±0.0 + * ±0.0 < 0.0 ±π + * ±0.0 -0.0 ±π + * > 0.0 ±0.0 π/2 + * < 0.0 ±0.0 π/2 + * > 0.0 ∞ ±0.0 + * ±∞ anything ±π/2 + * > 0.0 -∞ ±π + * ±∞ ∞ ±π/4 + * ±∞ -∞ ±3π/4 * ) */ -real atan2(real x, real y) { return std.c.math.atan2l(x,y); } +real atan2(real y, real x) { return std.c.math.atan2l(y,x); } /*********************************** * Calculates the hyperbolic cosine of x. diff --git a/std/socket.d b/std/socket.d index 43fc829dc..51e4c368a 100644 --- a/std/socket.d +++ b/std/socket.d @@ -1593,3 +1593,47 @@ class Socket +/ } + +/// TcpSocket is a shortcut class for a TCP Socket. +class TcpSocket: Socket +{ + /// Constructs a blocking TCP Socket. + this(AddressFamily family) + { + super(family, SocketType.STREAM, ProtocolType.TCP); + } + + /// Constructs a blocking TCP Socket. + this() + { + this(cast(AddressFamily)AddressFamily.INET); + } + + + //shortcut + /// Constructs a blocking TCP Socket and connects to an InternetAddress. + this(Address connectTo) + { + this(connectTo.addressFamily()); + connect(connectTo); + } +} + + +/// UdpSocket is a shortcut class for a UDP Socket. +class UdpSocket: Socket +{ + /// Constructs a blocking UDP Socket. + this(AddressFamily family) + { + super(family, SocketType.DGRAM, ProtocolType.UDP); + } + + + /// Constructs a blocking UDP Socket. + this() + { + this(cast(AddressFamily)AddressFamily.INET); + } +} + diff --git a/std/string.d b/std/string.d index cc91551e8..c5441eb88 100644 --- a/std/string.d +++ b/std/string.d @@ -76,7 +76,7 @@ const dchar PS = '\u2029'; /// UTF paragraph separator version (Windows) const char[2] newline = "\r\n"; else version (linux) - const char[2] newline = "\n"; + const char[1] newline = "\n"; /********************************** * Returns !=0 if c is whitespace diff --git a/std/traits.d b/std/traits.d index 04f123309..a4d20c24b 100644 --- a/std/traits.d +++ b/std/traits.d @@ -11,8 +11,10 @@ * Public Domain */ -/* Author: +/* + * Authors: * Walter Bright, Digital Mars, www.digitalmars.com + * Tomasz Stachowiak (isStaticArray, isExpressionTuple) */ module std.traits; @@ -125,3 +127,57 @@ unittest assert(is (TL[1] == I)); } +/* ******************************************* + */ +template isStaticArray_impl(T) +{ + const T inst = void; + + static if (is(typeof(T.length))) + { + static if (!is(typeof(T) == typeof(T.init))) + { // abuses the fact that int[5].init == int + static if (is(T == typeof(T[0])[inst.length])) + { // sanity check. this check alone isn't enough because dmd complains about dynamic arrays + const bool res = true; + } + else + const bool res = false; + } + else + const bool res = false; + } + else + { + const bool res = false; + } +} +/** + * Detect whether type T is a static array. + */ +template isStaticArray(T) +{ + const bool isStaticArray = isStaticArray_impl!(T).res; +} + + +static assert (isStaticArray!(int[51])); +static assert (isStaticArray!(int[][2])); +static assert (isStaticArray!(char[][int][11])); +static assert (!isStaticArray!(int[])); +static assert (!isStaticArray!(int[char])); +static assert (!isStaticArray!(int[1][])); + +/** + * Tells whether the tuple T is an expression tuple. + */ +template isExpressionTuple(T ...) +{ + static if (is(void function(T))) + const bool isExpressionTuple = false; + else + const bool isExpressionTuple = true; +} + + + diff --git a/std/typeinfo/ti_Aubyte.d b/std/typeinfo/ti_Aubyte.d index 9ee9ce35c..138190bbf 100644 --- a/std/typeinfo/ti_Aubyte.d +++ b/std/typeinfo/ti_Aubyte.d @@ -83,7 +83,7 @@ class TypeInfo_Av : TypeInfo_Ah // bool[] -class TypeInfo_Ax : TypeInfo_Ah +class TypeInfo_Ab : TypeInfo_Ah { char[] toString() { return "bool[]"; } } diff --git a/std/typeinfo/ti_ubyte.d b/std/typeinfo/ti_ubyte.d index f7eb051db..2940c7773 100644 --- a/std/typeinfo/ti_ubyte.d +++ b/std/typeinfo/ti_ubyte.d @@ -37,7 +37,7 @@ class TypeInfo_h : TypeInfo } } -class TypeInfo_x : TypeInfo_h +class TypeInfo_b : TypeInfo_h { char[] toString() { return "bool"; } } diff --git a/win32.mak b/win32.mak index 08d4ee5d9..9858da4cc 100644 --- a/win32.mak +++ b/win32.mak @@ -74,7 +74,7 @@ OBJS= asserterror.obj deh.obj switch.obj complex.obj gcstats.obj \ perf.obj openrj.obj uni.obj winsock.obj oldsyserror.obj \ errno.obj boxer.obj cstream.obj charset.obj \ gamma.obj demangle.obj cover.obj bitarray.obj aApplyR.obj \ - signals.obj cpuid.obj typetuple.obj traits.obj \ + signals.obj cpuid.obj typetuple.obj traits.obj bind.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 \ @@ -95,6 +95,7 @@ DOCS= $(DOC)\std_path.html $(DOC)\std_math.html $(DOC)\std_outbuffer.html \ $(DOC)\object.html $(DOC)\std_compiler.html $(DOC)\std_format.html \ $(DOC)\std_random.html $(DOC)\std_file.html $(DOC)\std_date.html \ $(DOC)\std_md5.html $(DOC)\std_zip.html $(DOC)\std_zlib.html \ + $(DOC)\std_bind.html \ $(DOC)\std_bitarray.html \ $(DOC)\std_conv.html \ $(DOC)\std_boxer.html \ @@ -148,7 +149,7 @@ SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.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\boxer.d \ std\cstream.d std\demangle.d std\cover.d std\bitarray.d \ - std\signals.d std\cpuid.d std\typetuple.d std\traits.d + std\signals.d std\cpuid.d std\typetuple.d std\traits.d std\bind.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\fenv.d std\c\string.d \ @@ -339,6 +340,9 @@ asserterror.obj : std\asserterror.d base64.obj : std\base64.d $(DMD) -c $(DFLAGS) -inline std\base64.d +bind.obj : std\bind.d + $(DMD) -c $(DFLAGS) -inline std\bind.d + bitarray.obj : std\bitarray.d $(DMD) -c $(DFLAGS) -inline std\bitarray.d @@ -663,6 +667,9 @@ $(DOC)\phobos.html : std.ddoc phobos.d $(DOC)\std_base64.html : std.ddoc std\base64.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_base64.html std.ddoc std\base64.d +$(DOC)\std_bind.html : std.ddoc std\bind.d + $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_bind.html std.ddoc std\bind.d + $(DOC)\std_bitarray.html : std.ddoc std\bitarray.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_bitarray.html std.ddoc std\bitarray.d