egra: checkbox fixes
[iv.d.git] / follin / cmacro.d
blobb7dc5f420d3c0b30439c6d4e460ebdb9d2706934
1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv.follin.cmacro /*is aliced*/;
18 import iv.alice;
21 // cool helper to translate C defines
22 template cmacroFixVars(T...) {
23 /**
24 * 64-bit implementation of fasthash
26 * Params:
27 * buf = data buffer
28 * seed = the seed
30 * Returns:
31 * 32-bit or 64-bit hash
33 usize hashBuffer (const(void)* buf, usize len, usize seed=0) pure nothrow @trusted @nogc {
34 enum Get8Bytes = q{
35 cast(ulong)data[0]|
36 (cast(ulong)data[1]<<8)|
37 (cast(ulong)data[2]<<16)|
38 (cast(ulong)data[3]<<24)|
39 (cast(ulong)data[4]<<32)|
40 (cast(ulong)data[5]<<40)|
41 (cast(ulong)data[6]<<48)|
42 (cast(ulong)data[7]<<56)
44 enum m = 0x880355f21e6d1965UL;
45 auto data = cast(const(ubyte)*)buf;
46 ulong h = seed;
47 ulong t;
48 foreach (immutable _; 0..len/8) {
49 version(HasUnalignedOps) {
50 if (__ctfe) {
51 t = mixin(Get8Bytes);
52 } else {
53 t = *cast(ulong*)data;
55 } else {
56 t = mixin(Get8Bytes);
58 data += 8;
59 t ^= t>>23;
60 t *= 0x2127599bf4325c37UL;
61 t ^= t>>47;
62 h ^= t;
63 h *= m;
66 h ^= len*m;
67 t = 0;
68 switch (len&7) {
69 case 7: t ^= cast(ulong)data[6]<<48; goto case 6;
70 case 6: t ^= cast(ulong)data[5]<<40; goto case 5;
71 case 5: t ^= cast(ulong)data[4]<<32; goto case 4;
72 case 4: t ^= cast(ulong)data[3]<<24; goto case 3;
73 case 3: t ^= cast(ulong)data[2]<<16; goto case 2;
74 case 2: t ^= cast(ulong)data[1]<<8; goto case 1;
75 case 1: t ^= cast(ulong)data[0]; goto default;
76 default:
77 t ^= t>>23;
78 t *= 0x2127599bf4325c37UL;
79 t ^= t>>47;
80 h ^= t;
81 h *= m;
82 break;
85 h ^= h>>23;
86 h *= 0x2127599bf4325c37UL;
87 h ^= h>>47;
88 static if (usize.sizeof == 4) {
89 // 32-bit hash
90 // the following trick converts the 64-bit hashcode to Fermat
91 // residue, which shall retain information from both the higher
92 // and lower parts of hashcode.
93 return cast(usize)(h-(h>>32));
94 } else {
95 return h;
99 string cmacroFixVars (string s, string[] names...) {
100 assert(T.length == names.length, "cmacroFixVars: names and arguments count mismatch");
101 enum tmpPfxName = "__temp_prefix__";
102 string res;
103 string tmppfx;
104 uint pos = 0;
105 // skip empty lines (for pretty printing)
106 // trim trailing spaces
107 while (s.length > 0 && s[$-1] <= ' ') s = s[0..$-1];
108 uint linestpos = 0; // start of the current line
109 while (pos < s.length) {
110 if (s[pos] > ' ') break;
111 if (s[pos] == '\n') linestpos = pos+1;
112 ++pos;
114 pos = linestpos;
115 while (pos+2 < s.length) {
116 int epos = pos;
117 while (epos+2 < s.length && (s[epos] != '$' || s[epos+1] != '{')) ++epos;
118 if (epos > pos) {
119 if (s.length-epos < 3) break;
120 res ~= s[pos..epos];
121 pos = epos;
123 assert(s[pos] == '$' && s[pos+1] == '{');
124 pos += 2;
125 bool found = false;
126 if (s.length-pos >= tmpPfxName.length+1 && s[pos+tmpPfxName.length] == '}' && s[pos..pos+tmpPfxName.length] == tmpPfxName) {
127 if (tmppfx.length == 0) {
128 // generate temporary prefix
129 auto hash = hashBuffer(s.ptr, s.length);
130 immutable char[16] hexChars = "0123456789abcdef";
131 tmppfx = "_temp_macro_var_";
132 foreach_reverse (immutable idx; 0..usize.sizeof*2) {
133 tmppfx ~= hexChars[hash&0x0f];
134 hash >>= 4;
136 tmppfx ~= "_";
138 pos += tmpPfxName.length+1;
139 res ~= tmppfx;
140 found = true;
141 } else {
142 foreach (immutable nidx, string oname; T) {
143 static assert(oname.length > 0);
144 if (s.length-pos >= oname.length+1 && s[pos+oname.length] == '}' && s[pos..pos+oname.length] == oname) {
145 found = true;
146 pos += oname.length+1;
147 res ~= names[nidx];
148 break;
152 assert(found, "unknown variable in macro");
154 if (pos < s.length) res ~= s[pos..$];
155 return res;
161 //void draw_line (float* ${output}, int ${x0}, int ${y0}, int ${x1}, int ${y1}, int ${n})
162 enum draw_line(string output, string x0, string y0, string x1, string y1, string n) = q{{
163 int ${__temp_prefix__}dy = ${y1}-${y0};
164 int ${__temp_prefix__}adx = ${x1}-${x0};
165 int ${__temp_prefix__}ady = mixin(ABS!"${__temp_prefix__}dy");
166 int ${__temp_prefix__}base;
167 int ${__temp_prefix__}x = ${x0}, ${__temp_prefix__}y = ${y0};
168 int ${__temp_prefix__}err = 0;
169 int ${__temp_prefix__}sy;
171 version(STB_VORBIS_DIVIDE_TABLE) {
172 if (${__temp_prefix__}adx < DIVTAB_DENOM && ${__temp_prefix__}ady < DIVTAB_NUMER) {
173 if (${__temp_prefix__}dy < 0) {
174 ${__temp_prefix__}base = -integer_divide_table[${__temp_prefix__}ady][${__temp_prefix__}adx];
175 ${__temp_prefix__}sy = ${__temp_prefix__}base-1;
176 } else {
177 ${__temp_prefix__}base = integer_divide_table[${__temp_prefix__}ady][${__temp_prefix__}adx];
178 ${__temp_prefix__}sy = ${__temp_prefix__}base+1;
180 } else {
181 ${__temp_prefix__}base = ${__temp_prefix__}dy/${__temp_prefix__}adx;
182 ${__temp_prefix__}sy = ${__temp_prefix__}base+(${__temp_prefix__}dy < 0 ? -1 : 1);
184 } else {
185 ${__temp_prefix__}base = ${__temp_prefix__}dy/${__temp_prefix__}adx;
186 ${__temp_prefix__}sy = ${__temp_prefix__}base+(${__temp_prefix__}dy < 0 ? -1 : 1);
188 ${__temp_prefix__}ady -= mixin(ABS!"${__temp_prefix__}base")*${__temp_prefix__}adx;
189 if (${x1} > ${n}) ${x1} = ${n};
190 mixin(LINE_OP!("${output}[${__temp_prefix__}x]", "inverse_db_table[${__temp_prefix__}y]"));
191 for (++${__temp_prefix__}x; ${__temp_prefix__}x < ${x1}; ++${__temp_prefix__}x) {
192 ${__temp_prefix__}err += ${__temp_prefix__}ady;
193 if (${__temp_prefix__}err >= ${__temp_prefix__}adx) {
194 ${__temp_prefix__}err -= ${__temp_prefix__}adx;
195 ${__temp_prefix__}y += ${__temp_prefix__}sy;
196 } else {
197 ${__temp_prefix__}y += ${__temp_prefix__}base;
199 mixin(LINE_OP!("${output}[${__temp_prefix__}x]", "inverse_db_table[${__temp_prefix__}y]"));
201 }}.cmacroFixVars!("output", "x0", "y0", "x1", "y1", "n")(output, x0, y0, x1, y1, n);