[Issue 5494] New: [patch,enh] Issues with std.stdarg
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Wed Jan 26 23:58:56 PST 2011
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: nobody at puremagic.com
ReportedBy: sandford at jhu.edu
--- Comment #0 from Rob Jacques <sandford at 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: -------
More information about the Digitalmars-d-bugs
mailing list