http://d.puremagic.com/issues/show_bug.cgi?id=5494

           Summary: [patch,enh] Issues with std.stdarg
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Keywords: patch
          Severity: enhancement
          Priority: P3
         Component: Phobos
        AssignedTo: nob...@puremagic.com
        ReportedBy: sandf...@jhu.edu


--- Comment #0 from Rob Jacques <sandf...@jhu.edu> 2011-01-26 23:56:47 PST ---
Currently, std.stdarg doesn't appear to be 64-bit safe (see Issue 4310) is
extremely limited in functionality, and although mentioned in passing in the
D-style Variadic Functions documentation, it isn't listed as a Phobos module.
With regard to functionality, std.stdarg contains a single function ("va_arg")
which interprets _argptr as a pointer to type T, returns a T and advances
_argptr by T.sizeof adjusted to 32-bit alignment (see Issue 4310). This is
unsafe, as _argptr may not actually be T* and therefore will be mis-aligned
post va_arg. Given that D provides type safe Variadic Functions via the
_arguments TypeInfo[], a better solution whould be to use the correct
TypeInfo.tsize when advancing _argptr. Further more, there are use cases
(std.boxer/std.variant, etc) which work with void*/TypeInfo directly and must
currently maintain correct stack alignment manually. As a solution to these
issues, I'm proposing the VariadicArguments range listed below. Note that
switching the assert in get to enforce should allow all methods to be @trusted
or @safe.


/** Iterates a set of D-style variadic function arguments in a safe manner.
 * Example:
 * --------
    void foo(...) {
        auto va_args = VariadicArguments(_arguments,_argptr) ;
        assert(va_args.length == 6);
        assert(va_args.get!uint   == 1); va_args.popFront;
        assert(va_args.get!int    == 2); va_args.popFront;
        assert(va_args.get!long   == 3); va_args.popFront;
        assert(va_args.get!float  == 4); va_args.popFront;
        assert(va_args.get!double == 5); va_args.popFront;
        assert(va_args.get!real   == 6); va_args.popFront;
    }
    foo(1u,2,3L,4f,5.0,6.0L);
 * --------
 */
struct VariadicArguments {
    private TypeInfo[] args;
    private void*      ptr;

    this(TypeInfo[] arguments, void* argptr) {
        args = arguments;
        ptr  = argptr;
    }

    /// Returns: true if there are no more arguments
    bool empty() const nothrow { return args.empty; }

    /// Returns: a copy of this.
          VariadicArguments  save()       nothrow { return this; }
    const(VariadicArguments) save() const nothrow { return this; } ///ditto

    /// Advances to the next argument
    void popFront() {
        ptr = ptr + ((args.front.tsize + size_t.sizeof - 1) & ~(size_t.sizeof -
1));
        args.popFront;
    }

    /// Returns: a tuple of an untyped pointer to the current argument and it's
TypeInfo.
    Tuple!(void*,TypeInfo) front() { return tuple(ptr,args.front); }


    /// Returns: the number of arguments
    size_t length() const nothrow { return args.length; }

    /// Returns: the current argument interpreted as type T
    T get(T)() nothrow {
        assert(typeid(T).toString() == args.front.toString(),
               "VariadicArguments.get: mis-matching types:
"~typeid(T).toString~" vs. "~args.front.toString);
        return *cast(T*)ptr;
    }
}

unittest {
    void foo(...) {
        auto va_args = VariadicArguments(_arguments,_argptr) ;
        assert(va_args.length == 6);
        assert(va_args.get!uint   == 1); va_args.popFront;
        assert(va_args.get!int    == 2); va_args.popFront;
        assert(va_args.get!long   == 3); va_args.popFront;
        assert(va_args.get!float  == 4); va_args.popFront;
        assert(va_args.get!double == 5); va_args.popFront;
        assert(va_args.get!real   == 6); va_args.popFront;
    }
    foo(1u,2,3L,4f,5.0,6.0L);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------

Reply via email to