Created
April 1, 2015 12:13
-
-
Save yebblies/89845dc99c50e41d6d6a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.stdio; | |
import std.process; | |
import std.random; | |
import std.exception; | |
import std.uuid; | |
import std.range; | |
import std.string; | |
// x86_32 - bug with empty struct - fixed | |
// x86_64 posix - bug with empty struct (https://issues.dlang.org/show_bug.cgi?id=13956) | |
// x86_64 posix - bug with float+double struct (https://issues.dlang.org/show_bug.cgi?id=13955) | |
// x86_64 posix - bug with double+char struct (not reduced, probably similar) | |
// x86_64 posix - more? | |
abstract | |
class Value | |
{ | |
// void writeCheckCpp(ref File f, string prefix, size_t i); | |
// void writeCheckD(ref File f, string prefix, size_t i); | |
void writeStructCpp(ref File f); | |
void writeStructD(ref File f); | |
void writeMemberCpp(ref File f, size_t i); | |
void writeMemberD(ref File f, size_t i); | |
void writeParamD(ref File f, size_t i); | |
void writeParamPromotedD(ref File f, size_t i); | |
void writeVarD(ref File f, size_t i, bool value); | |
void writeVarPromotedD(ref File f, size_t i, bool value); | |
void writeTypeD(ref File f, size_t i); | |
void writeTypePromotedD(ref File f, size_t i); | |
void writeInitD(ref File f); | |
void writeParamCpp(ref File f, size_t i); | |
void writeParamPromotedCpp(ref File f, size_t i); | |
void writeVarPromotedCpp(ref File f, size_t i); | |
void writeTypePromotedCpp(ref File f, size_t i); | |
void writeFormat(ref File f, size_t i); | |
} | |
class Struct : Value | |
{ | |
string name; | |
Value[] members; | |
this(string name) | |
{ | |
this.name = name; | |
} | |
// override void writeCheckCpp(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix); | |
// } | |
// override void writeCheckD(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix); | |
// } | |
override void writeStructCpp(ref File f) | |
{ | |
foreach(i, m; members) | |
m.writeStructCpp(f); | |
f.writefln("struct %s {", name); | |
foreach(i, m; members) | |
m.writeMemberCpp(f, i); | |
f.writefln("};"); | |
f.writefln(""); | |
} | |
override void writeStructD(ref File f) | |
{ | |
foreach(i, m; members) | |
m.writeStructD(f); | |
f.writefln("struct %s {", name); | |
foreach(i, m; members) | |
m.writeMemberD(f, i); | |
f.writefln("}"); | |
f.writefln(""); | |
} | |
override void writeMemberCpp(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", name, mname); | |
} | |
override void writeMemberD(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", name, mname); | |
} | |
override void writeParamD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamPromotedD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamPromotedCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeTypeD(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeTypePromotedD(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeTypePromotedCpp(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeVarD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
{ | |
f.writef(" %s arg%d = ", name, i); | |
writeInitD(f); | |
f.writeln(";"); | |
} | |
else | |
f.writefln(" %s arg%d;", name, i); | |
} | |
override void writeVarPromotedD(ref File f, size_t i, bool value) | |
{ | |
writeVarD(f, i, value); | |
} | |
override void writeVarPromotedCpp(ref File f, size_t i) | |
{ | |
f.writefln(" %s arg%d;", name, i); | |
} | |
override void writeInitD(ref File f) | |
{ | |
f.writef("%s(", name); | |
foreach(i, m; members) | |
{ | |
if (i) | |
f.write(", "); | |
m.writeInitD(f); | |
} | |
f.writef(")"); | |
} | |
override void writeFormat(ref File f, size_t i) | |
{ | |
} | |
} | |
class Basic : Value | |
{ | |
string dname; | |
string cname; | |
string ival; | |
string dprom; | |
string cprom; | |
string format; | |
this(string dname, string cname, string ival, string dprom, string cprom, string format) | |
{ | |
this.dname = dname; | |
this.cname = cname; | |
this.ival = ival; | |
this.dprom = dprom; | |
this.cprom = cprom; | |
this.format = format; | |
} | |
// override void writeCheckCpp(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix); | |
// } | |
// override void writeCheckD(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix); | |
// } | |
override void writeStructCpp(ref File f) | |
{ | |
} | |
override void writeStructD(ref File f) | |
{ | |
} | |
override void writeMemberCpp(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", cname, mname); | |
} | |
override void writeMemberD(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", dname, mname); | |
} | |
override void writeParamD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", dname, i); | |
} | |
override void writeParamPromotedD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", dprom, i); | |
} | |
override void writeParamCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", cname, i); | |
} | |
override void writeParamPromotedCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", cprom, i); | |
} | |
override void writeTypeD(ref File f, size_t i) | |
{ | |
f.writef("%s", dname); | |
} | |
override void writeTypePromotedD(ref File f, size_t i) | |
{ | |
f.writef("%s", dprom); | |
} | |
override void writeTypePromotedCpp(ref File f, size_t i) | |
{ | |
f.writef("%s", cprom); | |
} | |
override void writeVarD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
f.writefln(" %s arg%d = %s;", dname, i, ival); | |
else | |
f.writefln(" %s arg%d;", dname, i); | |
} | |
override void writeVarPromotedD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
f.writefln(" %s arg%d = %s;", dprom, i, ival); | |
else | |
f.writefln(" %s arg%d;", dprom, i); | |
} | |
override void writeVarPromotedCpp(ref File f, size_t i) | |
{ | |
f.writefln(" %s arg%d;", cprom, i); | |
} | |
override void writeInitD(ref File f) | |
{ | |
f.writef("%s", ival); | |
} | |
override void writeFormat(ref File f, size_t i) | |
{ | |
f.writef(" printf(\"%s\\n\", arg%s);", format, i); | |
} | |
} | |
version(D_LP64) | |
{ | |
static immutable string[6][] basics = | |
[ | |
["byte", "signed char", "99", "int", "int", "%d"], | |
["ubyte", "unsigned char", "100", "int", "int", "%d"], | |
["char", "char", "101", "int", "int", "%d"], | |
["int", "int", "102", "int", "int", "%d"], | |
["uint", "unsigned", "103", "uint", "unsigned", "%u"], | |
["long", "long", "104", "long", "long", "%ld"], | |
["ulong", "unsigned long", "105", "ulong", "unsigned long", "%lu"], | |
["float", "float", "2", "double", "double", "%f"], | |
["double", "double", "4", "double", "double", "%f"], | |
["real", "long double", "8", "real", "long double", "%Lf"], | |
["bool", "bool", "false", "int", "int", "%d"], | |
["void*", "void*", "null", "void*", "void*", "%p"], | |
]; | |
} | |
else version(X86) | |
{ | |
static immutable string[6][] basics = | |
[ | |
["byte", "signed char", "99", "int", "int", "%d"], | |
["ubyte", "unsigned char", "100", "int", "int", "%d"], | |
["char", "char", "101", "int", "int", "%d"], | |
["int", "int", "102", "int", "int", "%d"], | |
["uint", "unsigned", "103", "uint", "unsigned", "%u"], | |
["long", "long long", "104", "long", "long long", "%lld"], | |
["ulong", "unsigned long long", "105", "ulong", "unsigned long long", "%llu"], | |
["float", "float", "0", "double", "double", "%f"], | |
["double", "double", "0", "double", "double", "%f"], | |
["real", "long double", "0", "real", "long double", "%Lf"], | |
["bool", "bool", "false", "int", "int", "%d"], | |
["void*", "void*", "null", "void*", "void*", "%p"], | |
]; | |
} | |
Value genValue(bool allowstruct) | |
{ | |
auto p = uniform(0, basics.length+allowstruct); | |
if (p == basics.length) | |
{ | |
static int id; | |
while(true) | |
{ | |
auto s = genStruct("S%d".format(id++)); | |
bool hasfloat; | |
bool hasint; | |
foreach(_m; s.members) | |
{ | |
auto m = cast(Basic)_m; | |
if (m.dname == "float" || | |
m.dname == "double" || | |
m.dname == "real") | |
{ | |
hasfloat = true; | |
} | |
else | |
{ | |
hasint = true; | |
} | |
} | |
if (!hasfloat || !hasint) | |
return s; | |
} | |
} | |
else | |
{ | |
return new Basic(basics[p][0], basics[p][1], basics[p][2], basics[p][3], basics[p][4], basics[p][5]); | |
} | |
} | |
Struct genStruct(string name) | |
{ | |
auto s = new Struct(name); | |
// modify here to change the number of struct members | |
foreach(i; 0..uniform!"[]"(1, 10)) | |
{ | |
s.members ~= genValue(false); | |
} | |
return s; | |
} | |
void main() | |
{ | |
while(true) | |
{ | |
auto testname = "test_vararg_" ~ randomUUID().toString().replace("-", "_"); | |
Value[] values; | |
// modify here to change the number of parameters | |
values.length = uniform!"[]"(1, 20); | |
foreach(ref v; values) | |
v = genValue(true); | |
// modify here to change the number of named parameters | |
auto namedArgs = uniform!"[]"(1, values.length); | |
auto df = File(testname ~ "_d.d", "wb"); | |
auto cf = File(testname ~ "_cpp.cpp", "wb"); | |
df.writeln("import core.stdc.stdarg;"); | |
df.writeln("import core.stdc.stdio;"); | |
df.writeln(); | |
cf.writeln("#include <stdarg.h>"); | |
cf.writeln("#include <stdio.h>"); | |
cf.writeln(); | |
foreach(v; values) | |
{ | |
v.writeStructCpp(cf); | |
v.writeStructD(df); | |
} | |
cf.write("void checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
v.writeParamCpp(cf, i); | |
else | |
v.writeParamPromotedCpp(cf, i); | |
} | |
cf.writeln(");"); | |
// cf.writeln("int main(void) {"); | |
// cf.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckCpp(cf, "s", i); | |
// cf.writefln("printf(\"size: %%d\\n\", sizeof(s));"); | |
// cf.writeln("\treturn 0;"); | |
// cf.writeln("}"); | |
cf.write("void cppvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamCpp(cf, i); | |
if (values.length != namedArgs) | |
cf.writeln(", ...)"); | |
else | |
cf.writeln(")"); | |
cf.writeln("{"); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
v.writeVarPromotedCpp(cf, i); | |
} | |
if (values.length != namedArgs) | |
{ | |
cf.writeln(" va_list va;"); | |
cf.writefln(" va_start(va, arg%d);", namedArgs-1); | |
} | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
cf.writef(" arg%d = va_arg(va, ", i); | |
v.writeTypePromotedCpp(cf, i); | |
cf.writefln(");"); | |
} | |
if (values.length != namedArgs) | |
{ | |
cf.writeln(" va_end(va);"); | |
} | |
cf.writeln(" printf(\"======= cppvararg =======\\n\");"); | |
foreach(i, v; values) | |
{ | |
v.writeFormat(cf, i); | |
} | |
cf.write(" checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
cf.write(", "); | |
cf.writef("arg%d", i); | |
} | |
cf.writeln(");"); | |
cf.writeln("}"); | |
cf.writeln(); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void cppvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamD(df, i); | |
if (values.length > namedArgs) | |
df.writeln(", ...);"); | |
else | |
df.writeln(");"); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void dvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamD(df, i); | |
if (values.length != namedArgs) | |
df.writeln(", ...)"); | |
else | |
df.writeln(")"); | |
df.writeln("{"); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
v.writeVarPromotedD(df, i, false); | |
} | |
if (values.length != namedArgs) | |
{ | |
df.writeln(" va_list va;"); | |
df.writefln(" va_start(va, arg%d);", namedArgs-1); | |
} | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
df.write(" va_arg!("); | |
v.writeTypePromotedD(df, i); | |
df.writefln(")(va, arg%d);", i); | |
} | |
if (values.length != namedArgs) | |
{ | |
df.writeln(" va_end(va);"); | |
} | |
df.write(" checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
v.writeParamD(df, i); | |
else | |
v.writeParamPromotedD(df, i); | |
} | |
df.writeln(")"); | |
df.writeln("{"); | |
df.writeln(" printf(\"======= checkValues =======\\n\");"); | |
foreach(i, v; values) | |
{ | |
v.writeFormat(df, i); | |
} | |
foreach(i, v; values) | |
{ | |
df.writef(" assert(arg%d == ", i); | |
v.writeInitD(df); | |
df.writeln(");"); | |
} | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
df.writeln("void main()"); | |
df.writeln("{"); | |
foreach(i, v; values) | |
{ | |
v.writeVarD(df, i, true); | |
} | |
df.write(" dvararg("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.write(" cppvararg("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
// df.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckD(df, "s", i); | |
// df.writefln("printf(\"size: %%d\\n\", s.sizeof);"); | |
// df.writeln("}"); | |
// df.writeln("void main() {"); | |
// df.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckD(df, "s", i); | |
// df.writefln("printf(\"size: %%d\\n\", s.sizeof);"); | |
// df.writeln("}"); | |
cf.close(); | |
df.close(); | |
version(Windows) | |
{ | |
writeln("%s_d.d".format(testname)); | |
auto dmcres = executeShell("dmc -g -c %s_cpp.cpp".format(testname)); | |
writeln(dmcres.output); | |
enforce(dmcres.status == 0); | |
auto dmdres = executeShell("dmd -g %s_d.d %s_cpp.obj".format(testname, testname)); | |
writeln(dmdres.output); | |
enforce(dmdres.status == 0); | |
auto dout = executeShell("%s_d".format(testname)); | |
} | |
else | |
{ | |
writeln("%s_d.d".format(testname)); | |
auto gppres = executeShell("g++ -g %s_cpp.cpp -c -o %s_cpp.o".format(testname, testname)); | |
writeln(gppres.output); | |
enforce(gppres.status == 0); | |
auto dmdres = executeShell("CC=g++ ./dmd -gc %s_d.d %s_cpp.o".format(testname, testname)); | |
writeln(dmdres.output); | |
enforce(dmdres.status == 0); | |
auto dout = executeShell("./%s_d".format(testname)); | |
} | |
if (dout.status != 0) | |
{ | |
writeln(dout.output); | |
enforce(dout.status == 0); | |
} | |
version(Windows) | |
{ | |
import std.file; | |
remove("%s_cpp.cpp".format(testname)); | |
remove("%s_cpp.obj".format(testname)); | |
remove("%s_d.d".format(testname)); | |
remove("%s_d.obj".format(testname)); | |
remove("%s_d.exe".format(testname)); | |
} | |
else | |
{ | |
import std.file; | |
remove("%s_cpp.cpp".format(testname)); | |
remove("%s_cpp.o".format(testname)); | |
remove("%s_d.d".format(testname)); | |
remove("%s_d.o".format(testname)); | |
remove("%s_d".format(testname)); | |
} | |
} | |
} | |
// extern(C++) void dvarArg(int arg0, ...) | |
// { | |
// long arg1; | |
// bool arg2; | |
// va_list va; | |
// va_start(va, arg0); | |
// va_arg!long(va, arg1); | |
// va_arg!bool(va, arg2); | |
// va_end(va); | |
// checkValues(arg0, arg1, arg2); | |
// } | |
// extern(C++) void checkValues(int arg0, long arg1, bool arg2) | |
// { | |
// assert(arg0 == 3); | |
// assert(arg1 == 7); | |
// assert(arg2 == false); | |
// } | |
// void main() | |
// { | |
// int arg0 = 3; | |
// long arg1 = 7; | |
// bool arg2 = false; | |
// dvarArg(arg0, arg1, arg2); | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment