digitalmars.D - The X Macro using D
- Walter Bright (108/108) Jul 20 2017 Some time ago, I wrote about the X Macro in C:
- Stefan Koch (5/52) Jul 20 2017 Please tell me this is not going to get into dmd :)
- Walter Bright (2/7) Jul 20 2017 If you like, present the CTFE solution. Should be fun!
- Stefan Koch (73/80) Jul 21 2017 My pleasure :)
- Jacob Carlborg (5/6) Jul 21 2017 My approach, without string mixin:
- Olivier FAURE (7/33) Jul 21 2017 Quick questions: isn't it possible to do
- Olivier FAURE (8/10) Jul 21 2017 I meant
- Jacob Carlborg (5/10) Jul 21 2017 Yes, that's basically what my solution is doing [1].
- Jacob Carlborg (40/48) Jul 21 2017 Here's my solution. It sill uses templates for the implementation of "ma...
- Stefan Koch (3/14) Jul 21 2017 that uses more compile-time then mine :)
- Jacob Carlborg (4/5) Jul 21 2017 Perhaps that should be fixed in the compiler ;)
- Enamex (68/75) Jul 21 2017 How about this (if I'm not mistaken, this's only one template
- Stefan Koch (3/8) Jul 22 2017 tuple map and array are all pretty expensive.
- Martin Nowak (8/10) Jul 22 2017 Well a bit more compile time isn't the end of the world, and by
- Patrick Schluter (14/20) Jul 21 2017 In C there's no point in the X macro anymore since C99.
- Nick Treleaven (4/9) Jul 21 2017 I don't see how this allows data for different arrays to be
- Nicholas Wilson (4/117) Jul 21 2017 I wonder if you could use one of the SoA implementations (e.g
- Johan Engelen (6/12) Jul 21 2017 This mechanism is used in LLVM in a number of places, where the
- Nicholas Wilson (2/16) Jul 21 2017 And those in turn are generated from TableGen.
Some time ago, I wrote about the X Macro in C: https://digitalmars.com/articles/b51.html I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation. (I suppose it could be done with C++ templates, but I'll leave that to Andrei or Eric Niebler <g>.) ================ C Version ================ // Macro trick to generate several parallel tables #define Y \ X("AH",4,mAX,TYuchar) \ X("AL",0,mAX,TYuchar) \ X("AX",8,mAX,TYushort) \ X("BH",7,mBX,TYuchar) \ X("BL",3,mBX,TYuchar) \ X("BP",13,0,TYushort) \ X("BX",11,mBX,TYushort) \ X("CH",5,mCX,TYuchar) \ X("CL",1,mCX,TYuchar) \ X("CX",9,mCX,TYushort) \ X("DH",6,mDX,TYuchar) \ X("DI",15,mDI,TYushort) \ X("DL",2,mDX,TYuchar) \ X("DX",10,mDX,TYushort) \ X("EAX",16,mAX,TYulong) \ X("EBP",21,0,TYulong) \ X("EBX",19,mBX,TYulong) \ X("ECX",17,mCX,TYulong) \ X("EDI",23,mDI,TYulong) \ X("EDX",18,mDX,TYulong) \ X("ESI",22,mSI,TYulong) \ X("ESP",20,0,TYulong) \ X("SI",14,mSI,TYushort) \ X("SP",12,0,TYushort) // Table for identifiers static const char *pseudotab[] = { #define X(id,reg,m,ty) id, Y #undef X }; // Register number to use in addressing mode unsigned char pseudoreg[] = { #define X(id,reg,m,ty) reg, Y #undef X }; // Mask to use for registers affected regm_t pseudomask[] = { #define X(id,reg,m,ty) m, Y #undef X }; // Table for type of pseudo register variable static unsigned char pseudoty[] = { #define X(id,reg,m,ty) mTYvolatile | ty, Y #undef X }; ================ D Version ================ /* 4 parallel tables using "X Macro" technique */ template Y(alias X) { enum Y = [ // id reg mask ty X!("AH", 4, mAX, TYuchar), X!("AL", 0, mAX, TYuchar), X!("AX", 8, mAX, TYushort), X!("BH", 7, mBX, TYuchar), X!("BL", 3, mBX, TYuchar), X!("BP", 13, 0, TYushort), X!("BX", 11, mBX, TYushort), X!("CH", 5, mCX, TYuchar), X!("CL", 1, mCX, TYuchar), X!("CX", 9, mCX, TYushort), X!("DH", 6, mDX, TYuchar), X!("DI", 15, mDI, TYushort), X!("DL", 2, mDX, TYuchar), X!("DX", 10, mDX, TYushort), X!("EAX", 16, mAX, TYulong), X!("EBP", 21, 0, TYulong), X!("EBX", 19, mBX, TYulong), X!("ECX", 17, mCX, TYulong), X!("EDI", 23, mDI, TYulong), X!("EDX", 18, mDX, TYulong), X!("ESI", 22, mSI, TYulong), X!("ESP", 20, 0, TYulong), X!("SI", 14, mSI, TYushort), X!("SP", 12, 0, TYushort), ]; } // Table for identifiers template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; } private __gshared const(char)*[24] pseudotab = Y!Xtab; // Register number to use in addressing mode template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; } __gshared ubyte[24] pseudoreg = Y!Xreg; // Mask to use for registers affected template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; } __gshared regm_t[24] pseudomask = Y!Xmask; // Table for type of pseudo register variable template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; } private __gshared const(tym_t)[24] pseudoty = Y!Xty;
Jul 20 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:template Y(alias X) { enum Y = [ // id reg mask ty X!("AH", 4, mAX, TYuchar), X!("AL", 0, mAX, TYuchar), X!("AX", 8, mAX, TYushort), X!("BH", 7, mBX, TYuchar), X!("BL", 3, mBX, TYuchar), X!("BP", 13, 0, TYushort), X!("BX", 11, mBX, TYushort), X!("CH", 5, mCX, TYuchar), X!("CL", 1, mCX, TYuchar), X!("CX", 9, mCX, TYushort), X!("DH", 6, mDX, TYuchar), X!("DI", 15, mDI, TYushort), X!("DL", 2, mDX, TYuchar), X!("DX", 10, mDX, TYushort), X!("EAX", 16, mAX, TYulong), X!("EBP", 21, 0, TYulong), X!("EBX", 19, mBX, TYulong), X!("ECX", 17, mCX, TYulong), X!("EDI", 23, mDI, TYulong), X!("EDX", 18, mDX, TYulong), X!("ESI", 22, mSI, TYulong), X!("ESP", 20, 0, TYulong), X!("SI", 14, mSI, TYushort), X!("SP", 12, 0, TYushort), ]; } // Table for identifiers template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; } private __gshared const(char)*[24] pseudotab = Y!Xtab; // Register number to use in addressing mode template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; } __gshared ubyte[24] pseudoreg = Y!Xreg; // Mask to use for registers affected template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; } __gshared regm_t[24] pseudomask = Y!Xmask; // Table for type of pseudo register variable template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; } private __gshared const(tym_t)[24] pseudoty = Y!Xty;Please tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.
Jul 20 2017
On 7/20/2017 2:21 PM, Stefan Koch wrote:Please tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.If you like, present the CTFE solution. Should be fun!
Jul 20 2017
On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:On 7/20/2017 2:21 PM, Stefan Koch wrote:My pleasure :) string itos(uint n) { char[] result = []; immutable len = 10; result.length = len; uint i = len - 1; while (n > 10) { result[i--] = cast(char) ('0' + (n % 10)); n /= 10; } result[i] = cast(char) ('0' + (n % 10)); return cast(string) result[i .. $]; } mixin((){ static struct X { string id; ubyte reg; uint mask; ubyte ty; } enum Y = [ // id reg mask ty X("AH", 4, mAX, TYuchar), X("AL", 0, mAX, TYuchar), X("AX", 8, mAX, TYushort), X("BH", 7, mBX, TYuchar), X("BL", 3, mBX, TYuchar), X("BP", 13, 0, TYushort), X("BX", 11, mBX, TYushort), X("CH", 5, mCX, TYuchar), X("CL", 1, mCX, TYuchar), X("CX", 9, mCX, TYushort), X("DH", 6, mDX, TYuchar), X("DI", 15, mDI, TYushort), X("DL", 2, mDX, TYuchar), X("DX", 10, mDX, TYushort), X("EAX", 16, mAX, TYulong), X("EBP", 21, 0, TYulong), X("EBX", 19, mBX, TYulong), X("ECX", 17, mCX, TYulong), X("EDI", 23, mDI, TYulong), X("EDX", 18, mDX, TYulong), X("ESI", 22, mSI, TYulong), X("ESP", 20, 0, TYulong), X("SI", 14, mSI, TYushort), X("SP", 12, 0, TYushort), ]; enum lns = itos(Y.length); string pseudotab = "\nprivate __gshared static immutable string[" ~ lns ~ "] pseudotab = ["; string pseudoreg = "\nprivate __gshared static immutable ubyte[" ~ lns ~ "] pseudoreg = ["; string pseudomask = "\nprivate __gshared static immutable regm_t[" ~ lns ~ "] pseudomask = ["; string pseudoty = "\nprivate __gshared static immutable ubyte[" ~ lns ~ "] pseudoty = ["; foreach(i, r; Y) { pseudotab ~= `"` ~ r.id ~ `", `; pseudoreg ~= itos(r.reg) ~ `, `; pseudomask ~= itos(r.mask) ~ `, `; pseudoty ~= itos(r.ty) ~ `, `; } pseudotab ~= "];\n"; pseudoreg ~= "];\n"; pseudomask ~= "];\n"; pseudoty ~= "];\n"; return pseudotab ~ pseudoreg ~ pseudomask ~ pseudoty; }());Please tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.If you like, present the CTFE solution. Should be fun!
Jul 21 2017
On 2017-07-21 10:06, Stefan Koch wrote:My pleasure :)My approach, without string mixin: http://forum.dlang.org/post/oksd27$1li9$1 digitalmars.com :) -- /Jacob Carlborg
Jul 21 2017
On Friday, 21 July 2017 at 08:06:09 UTC, Stefan Koch wrote:My pleasure :) // ... mixin((){ // ... enum Y = [ // id reg mask ty X("AH", 4, mAX, TYuchar), X("AL", 0, mAX, TYuchar), X("AX", 8, mAX, TYushort), X("BH", 7, mBX, TYuchar), X("BL", 3, mBX, TYuchar), // ... X("ESI", 22, mSI, TYulong), X("ESP", 20, 0, TYulong), X("SI", 14, mSI, TYushort), X("SP", 12, 0, TYushort), ]; enum lns = itos(Y.length); string pseudotab = "\nprivate __gshared static immutable string[" ~ lns ~ "] pseudotab = ["; foreach(i, r; Y) { pseudotab ~= `"` ~ r.id ~ `", `; } pseudotab ~= "];\n"; }());Quick questions: isn't it possible to do private __gshared const(char)*[24] pseudotab = Y.map!(x => x.id); instead? That seems like the most obvious and easy to read option; and in contrast to the other solutions proposed, it's closer to the Rule of Least Power.
Jul 21 2017
On Friday, 21 July 2017 at 12:27:35 UTC, Olivier FAURE wrote:private __gshared const(char)*[24] pseudotab = Y.map!(x => x.id);I meant private __gshared static immutable string[Y.length] pseudotab = Y.map!(x => x.id); but you get my point. Also, upon trying it, it doesn't seem to work (at least the immutable part doesn't), but I don't really understand why. All the variables in the expression are known at compile time.
Jul 21 2017
On 2017-07-21 14:27, Olivier FAURE wrote:Quick questions: isn't it possible to do private __gshared const(char)*[24] pseudotab = Y.map!(x => x.id); instead? That seems like the most obvious and easy to read option; and in contrast to the other solutions proposed, it's closer to the Rule of Least Power.Yes, that's basically what my solution is doing [1]. [1] http://forum.dlang.org/post/oksd27$1li9$1 digitalmars.com -- /Jacob Carlborg
Jul 21 2017
On 2017-07-21 00:02, Walter Bright wrote:On 7/20/2017 2:21 PM, Stefan Koch wrote:Here's my solution. It sill uses templates for the implementation of "map": auto map(alias func)(const(Row)[] array) { alias R = typeof(func(Row.init)); R[] result; foreach (e ; array) result ~= func(e); return result; } struct Row { string id; int reg; int mask; int ty; } immutable Row[2] table = [ Row("AH", 4, mAX, TYuchar), Row("AL", 0, mAX, TYuchar) ]; alias regm_t = int; alias tym_t = int; enum mAX = 1; enum TYuchar = 1; enum mTYvolatile = 2; private __gshared const(char)*[table.length] pseudotab = table.map!(row => row.id); __gshared ubyte[table.length] pseudoreg = table.map!(row => row.reg); __gshared int[table.length] pseudomask = table.map!(row => row.mask); private __gshared const(tym_t)[table.length] pseudoty = table.map!(row => mTYvolatile | row.ty); I added some type aliases and enums to be able to run the code self contained without DMD. Some advantages: * Less use of templates * More readable since there's a specific type (Row) with named fields, no need to write the fields in comments * Easier to update when the length of the arrays are not hard coded -- /Jacob CarlborgPlease tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.If you like, present the CTFE solution. Should be fun!
Jul 21 2017
On Friday, 21 July 2017 at 08:12:55 UTC, Jacob Carlborg wrote:On 2017-07-21 00:02, Walter Bright wrote:that uses more compile-time then mine :) and leaves bloat in the binary.On 7/20/2017 2:21 PM, Stefan Koch wrote:Here's my solution. It sill uses templates for the implementation of "map":Please tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.If you like, present the CTFE solution. Should be fun!
Jul 21 2017
On 2017-07-21 10:25, Stefan Koch wrote:and leaves bloat in the binary.Perhaps that should be fixed in the compiler ;) -- /Jacob Carlborg
Jul 21 2017
On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:On 7/20/2017 2:21 PM, Stefan Koch wrote:How about this (if I'm not mistaken, this's only one template instantiation per tuple-type&extracted-index): ```d import std.typecons: tuple, Tuple; import std.algorithm: map; import std.array: array; enum regm_t { AX, BX, CX, DX, DI, SI, None } enum tym_t { uchar_, ushort_, ulong_ } enum Ydata = [ tuple("AH", 4, regm_t.AX, tym_t.uchar_), tuple("AL", 0, regm_t.AX, tym_t.uchar_), tuple("AX", 8, regm_t.AX, tym_t.ushort_), tuple("BH", 7, regm_t.BX, tym_t.uchar_), tuple("BL", 3, regm_t.BX, tym_t.uchar_), tuple("BP", 13, regm_t.None, tym_t.ushort_), tuple("BX", 11, regm_t.BX, tym_t.ushort_), tuple("CH", 5, regm_t.CX, tym_t.uchar_), tuple("CL", 1, regm_t.CX, tym_t.uchar_), tuple("CX", 9, regm_t.CX, tym_t.ushort_), tuple("DH", 6, regm_t.DX, tym_t.uchar_), tuple("DI", 15, regm_t.DI, tym_t.ushort_), tuple("DL", 2, regm_t.DX, tym_t.uchar_), tuple("DX", 10, regm_t.DX, tym_t.ushort_), tuple("EAX", 16, regm_t.AX, tym_t.ulong_), tuple("EBP", 21, regm_t.None, tym_t.ulong_), tuple("EBX", 19, regm_t.BX, tym_t.ulong_), tuple("ECX", 17, regm_t.CX, tym_t.ulong_), tuple("EDI", 23, regm_t.DI, tym_t.ulong_), tuple("EDX", 18, regm_t.DX, tym_t.ulong_), tuple("ESI", 22, regm_t.SI, tym_t.ulong_), tuple("ESP", 20, regm_t.None, tym_t.ulong_), tuple("SI", 14, regm_t.SI, tym_t.ushort_), tuple("SP", 12, regm_t.None, tym_t.ushort_), ]; static auto Y(size_t idx, T...)(Tuple!(T)[] ts) pure nothrow { // I thought to try something like assumeUnique here // but was thinking of the Rust semantics in doing so // Not sure if this leads to spurious allocations at // the points where Y is used. Is there someway to tell them, // even if the target type is const or immutable // that this returned array is brand new with no other references // around? return ts .map!(x => x[idx]) .array ; } enum { Xtab = 0, Xreg, Xmask, Xty, } // Register number to use in addressing mode private __gshared const(char)*[24] pseudotab = Y!Xtab(Ydata); // Register number to use in addressing mode __gshared ubyte[24] pseudoreg = Y!Xreg(Ydata); // Mask to use for registers affected __gshared regm_t[24] pseudomask = Y!Xmask(Ydata); // Table for type of pseudo register variable private __gshared const(tym_t)[24] pseudoty = Y!Xty(Ydata); ```Please tell me this is not going to get into dmd :) templates are so much more expensive then macros. (Well, for now :) ) Those templates can and should be replaced by CTFE.If you like, present the CTFE solution. Should be fun!
Jul 21 2017
On Friday, 21 July 2017 at 20:44:13 UTC, Enamex wrote:On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:tuple map and array are all pretty expensive. please profile.[...]How about this (if I'm not mistaken, this's only one template instantiation per tuple-type&extracted-index): [...]
Jul 22 2017
On Saturday, 22 July 2017 at 11:50:40 UTC, Stefan Koch wrote:tuple map and array are all pretty expensive. please profile.Well a bit more compile time isn't the end of the world, and by far not the only metric (e.g. readability and maintainability also rank high). You're slightly obsessed with the template compile-time topic ;). BTW, the term expensive is fairly subjective easily misunderstood. Sth. more specific would reduce the chance for confusion, e.g. "tuple map and array require longer to compile"
Jul 22 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:Some time ago, I wrote about the X Macro in C: https://digitalmars.com/articles/b51.html I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.In C there's no point in the X macro anymore since C99. Designated initializer allow to do it properly[1] now. enum COLORS { red, blue, green, max }; char *cstring[max] = {[red]="red", [blue]="blue", [green]="green" }; /* C99 */ It works also with array indexes[2]. int a[3] = { [2]=1, [0]=3, [1]=2 }; /* C99 designated initializer */ int a[3] = { [2]=1, [0]=3, 2 }; /* C99 designated initializer */ C++ hasn't yet integrated. [1]: https://dlang.org/ctod.html#arrayenum [2]: https://dlang.org/ctod.html#arrayinit2
Jul 21 2017
On Friday, 21 July 2017 at 11:19:47 UTC, Patrick Schluter wrote:In C there's no point in the X macro anymore since C99. Designated initializer allow to do it properly[1] now. enum COLORS { red, blue, green, max }; char *cstring[max] = {[red]="red", [blue]="blue", [green]="green" }; /* C99 */I don't see how this allows data for different arrays to be written in interleaved form and then extracted by column to initialize the separate arrays, as Walter's does.
Jul 21 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:Some time ago, I wrote about the X Macro in C: https://digitalmars.com/articles/b51.html I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation. (I suppose it could be done with C++ templates, but I'll leave that to Andrei or Eric Niebler <g>.) ================ C Version ================ // Macro trick to generate several parallel tables #define Y \ X("AH",4,mAX,TYuchar) \ X("AL",0,mAX,TYuchar) \ X("AX",8,mAX,TYushort) \ X("BH",7,mBX,TYuchar) \ X("BL",3,mBX,TYuchar) \ X("BP",13,0,TYushort) \ X("BX",11,mBX,TYushort) \ X("CH",5,mCX,TYuchar) \ X("CL",1,mCX,TYuchar) \ X("CX",9,mCX,TYushort) \ X("DH",6,mDX,TYuchar) \ X("DI",15,mDI,TYushort) \ X("DL",2,mDX,TYuchar) \ X("DX",10,mDX,TYushort) \ X("EAX",16,mAX,TYulong) \ X("EBP",21,0,TYulong) \ X("EBX",19,mBX,TYulong) \ X("ECX",17,mCX,TYulong) \ X("EDI",23,mDI,TYulong) \ X("EDX",18,mDX,TYulong) \ X("ESI",22,mSI,TYulong) \ X("ESP",20,0,TYulong) \ X("SI",14,mSI,TYushort) \ X("SP",12,0,TYushort) // Table for identifiers static const char *pseudotab[] = { #define X(id,reg,m,ty) id, Y #undef X }; // Register number to use in addressing mode unsigned char pseudoreg[] = { #define X(id,reg,m,ty) reg, Y #undef X }; // Mask to use for registers affected regm_t pseudomask[] = { #define X(id,reg,m,ty) m, Y #undef X }; // Table for type of pseudo register variable static unsigned char pseudoty[] = { #define X(id,reg,m,ty) mTYvolatile | ty, Y #undef X }; ================ D Version ================ /* 4 parallel tables using "X Macro" technique */ template Y(alias X) { enum Y = [ // id reg mask ty X!("AH", 4, mAX, TYuchar), X!("AL", 0, mAX, TYuchar), X!("AX", 8, mAX, TYushort), X!("BH", 7, mBX, TYuchar), X!("BL", 3, mBX, TYuchar), X!("BP", 13, 0, TYushort), X!("BX", 11, mBX, TYushort), X!("CH", 5, mCX, TYuchar), X!("CL", 1, mCX, TYuchar), X!("CX", 9, mCX, TYushort), X!("DH", 6, mDX, TYuchar), X!("DI", 15, mDI, TYushort), X!("DL", 2, mDX, TYuchar), X!("DX", 10, mDX, TYushort), X!("EAX", 16, mAX, TYulong), X!("EBP", 21, 0, TYulong), X!("EBX", 19, mBX, TYulong), X!("ECX", 17, mCX, TYulong), X!("EDI", 23, mDI, TYulong), X!("EDX", 18, mDX, TYulong), X!("ESI", 22, mSI, TYulong), X!("ESP", 20, 0, TYulong), X!("SI", 14, mSI, TYushort), X!("SP", 12, 0, TYushort), ]; } // Table for identifiers template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; } private __gshared const(char)*[24] pseudotab = Y!Xtab; // Register number to use in addressing mode template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; } __gshared ubyte[24] pseudoreg = Y!Xreg; // Mask to use for registers affected template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; } __gshared regm_t[24] pseudomask = Y!Xmask; // Table for type of pseudo register variable template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; } private __gshared const(tym_t)[24] pseudoty = Y!Xty;I wonder if you could use one of the SoA implementations (e.g from here: https://wiki.dlang.org/Transforming_slice_of_structs_into_struct_of_slices) to the same effect.
Jul 21 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:Some time ago, I wrote about the X Macro in C: https://digitalmars.com/articles/b51.html I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.This mechanism is used in LLVM in a number of places, where the list entries are used e.g. to populate tables and to define aggregate member fields. For example: https://github.com/llvm-mirror/compiler-rt/blob/master/lib/profile/InstrProfData.inc#L29-L51
Jul 21 2017
On Friday, 21 July 2017 at 19:26:05 UTC, Johan Engelen wrote:On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:And those in turn are generated from TableGen.Some time ago, I wrote about the X Macro in C: https://digitalmars.com/articles/b51.html I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.This mechanism is used in LLVM in a number of places, where the list entries are used e.g. to populate tables and to define aggregate member fields. For example: https://github.com/llvm-mirror/compiler-rt/blob/master/lib/profile/InstrProfData.inc#L29-L51
Jul 21 2017