|
I never said it was.
Real programmers use butterflies
|
|
|
|
|
No, you didn't, it just seemed that way to me. I wouldn't even bother with C# in between, but that's a personal opinion, still trying to understand the logic though.
|
|
|
|
|
The reason I move it between unmanaged and managed code is it forces me to restructure it. I can't just get lazy and copypasta.
In the process of restructuring it, I grok it's machinations.
Furthermore, C# has a library for pretty much everything, so no matter what I'm doing in C++, there is pretty going to be the equiv in the .NET framework that I can rely on, so I can seal it off there and I don't have to import code like say, the code to do an HTTP request from C++, if that's not directly what I'm working on. I hope what I just wrote makes sense!
Real programmers use butterflies
|
|
|
|
|
Ok, thanks, my bad I don't even think of things such as .NET, it doesn't exist in my current life. If I can't find a suitable library, I have to create the functionality. It's just a completely different environment.
|
|
|
|
|
Besides, "cryptic" usually is a matter of who wrote it and how, not what language it happens to be in. Some of the most cryptic code I have run across was SQL written as a single line. Without parsing it, I would never have figured it out.
|
|
|
|
|
Yeah. I'm not trying to imply it's a particular language that's cryptic. It's all a matter of the code.
Real programmers use butterflies
|
|
|
|
|
UnchainedZA wrote: It's just a completely different environment.
That's exactly why I do it.
Real programmers use butterflies
|
|
|
|
|
in my head i port c# to c++ and then to c, so i can really understand
|
|
|
|
|
|
I have this precise issue in a legacy project I have inherited. The author wrote the code in a fashion that virtually guaranteed he was the only possible maintainer [approx. 4,000 words of obscenity-laden rant omitted].
On occasion I have copied the relevant source files to another folder and the reformatted and refactored mercilessly. The reformatting is to correct layout issues since his brace style and tabs weren't consistent (I've found tabs of 2, 3, 4, and 8 with tab characters). The refactoring is to give values meaningful names.
The reworked source code lets me understand how the original works when I need to make changes or understand how a feature works. Given the fragility of this towering pile of excreta, I don't use the reformatted code for anything other than my own understanding.
Software Zen: delete this;
|
|
|
|
|
I have only one thing to say in response, but it's a mouthful:
static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
{
int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
int has_subrs = 0, clear_stack;
float s[48];
stbtt__buf subr_stack[10], subrs = info->subrs, b;
float f;
#define STBTT__CSERR(s) (0)
b = stbtt__cff_index_get(info->charstrings, glyph_index);
while (b.cursor < b.size) {
i = 0;
clear_stack = 1;
b0 = stbtt__buf_get8(&b);
switch (b0) {
case 0x13: case 0x14: if (in_header)
maskbits += (sp / 2); in_header = 0;
stbtt__buf_skip(&b, (maskbits + 7) / 8);
break;
case 0x01: case 0x03: case 0x12: case 0x17: maskbits += (sp / 2);
break;
case 0x15: in_header = 0;
if (sp < 2) return STBTT__CSERR("rmoveto stack");
stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
break;
case 0x04: in_header = 0;
if (sp < 1) return STBTT__CSERR("vmoveto stack");
stbtt__csctx_rmove_to(c, 0, s[sp-1]);
break;
case 0x16: in_header = 0;
if (sp < 1) return STBTT__CSERR("hmoveto stack");
stbtt__csctx_rmove_to(c, s[sp-1], 0);
break;
case 0x05: if (sp < 2) return STBTT__CSERR("rlineto stack");
for (; i + 1 < sp; i += 2)
stbtt__csctx_rline_to(c, s[i], s[i+1]);
break;
case 0x07: if (sp < 1) return STBTT__CSERR("vlineto stack");
goto vlineto;
case 0x06: if (sp < 1) return STBTT__CSERR("hlineto stack");
for (;;) {
if (i >= sp) break;
stbtt__csctx_rline_to(c, s[i], 0);
i++;
vlineto:
if (i >= sp) break;
stbtt__csctx_rline_to(c, 0, s[i]);
i++;
}
break;
case 0x1F: if (sp < 4) return STBTT__CSERR("hvcurveto stack");
goto hvcurveto;
case 0x1E: if (sp < 4) return STBTT__CSERR("vhcurveto stack");
for (;;) {
if (i + 3 >= sp) break;
stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
i += 4;
hvcurveto:
if (i + 3 >= sp) break;
stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
i += 4;
}
break;
case 0x08: if (sp < 6) return STBTT__CSERR("rcurveline stack");
for (; i + 5 < sp; i += 6)
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
break;
case 0x18: if (sp < 8) return STBTT__CSERR("rcurveline stack");
for (; i + 5 < sp - 2; i += 6)
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
stbtt__csctx_rline_to(c, s[i], s[i+1]);
break;
case 0x19: if (sp < 8) return STBTT__CSERR("rlinecurve stack");
for (; i + 1 < sp - 6; i += 2)
stbtt__csctx_rline_to(c, s[i], s[i+1]);
if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
break;
case 0x1A: case 0x1B: if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
f = 0.0;
if (sp & 1) { f = s[i]; i++; }
for (; i + 3 < sp; i += 4) {
if (b0 == 0x1B)
stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
else
stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
f = 0.0;
}
break;
case 0x0A: if (!has_subrs) {
if (info->fdselect.size)
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
has_subrs = 1;
}
case 0x1D: if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
v = (int) s[--sp];
if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
subr_stack[subr_stack_height++] = b;
b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
if (b.size == 0) return STBTT__CSERR("subr not found");
b.cursor = 0;
clear_stack = 0;
break;
case 0x0B: if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
b = subr_stack[--subr_stack_height];
clear_stack = 0;
break;
case 0x0E: stbtt__csctx_close_shape(c);
return 1;
case 0x0C: { float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
float dx, dy;
int b1 = stbtt__buf_get8(&b);
switch (b1) {
case 0x22: if (sp < 7) return STBTT__CSERR("hflex stack");
dx1 = s[0];
dx2 = s[1];
dy2 = s[2];
dx3 = s[3];
dx4 = s[4];
dx5 = s[5];
dx6 = s[6];
stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
break;
case 0x23: if (sp < 13) return STBTT__CSERR("flex stack");
dx1 = s[0];
dy1 = s[1];
dx2 = s[2];
dy2 = s[3];
dx3 = s[4];
dy3 = s[5];
dx4 = s[6];
dy4 = s[7];
dx5 = s[8];
dy5 = s[9];
dx6 = s[10];
dy6 = s[11];
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
break;
case 0x24: if (sp < 9) return STBTT__CSERR("hflex1 stack");
dx1 = s[0];
dy1 = s[1];
dx2 = s[2];
dy2 = s[3];
dx3 = s[4];
dx4 = s[5];
dx5 = s[6];
dy5 = s[7];
dx6 = s[8];
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
break;
case 0x25: if (sp < 11) return STBTT__CSERR("flex1 stack");
dx1 = s[0];
dy1 = s[1];
dx2 = s[2];
dy2 = s[3];
dx3 = s[4];
dy3 = s[5];
dx4 = s[6];
dy4 = s[7];
dx5 = s[8];
dy5 = s[9];
dx6 = dy6 = s[10];
dx = dx1+dx2+dx3+dx4+dx5;
dy = dy1+dy2+dy3+dy4+dy5;
if (STBTT_fabs(dx) > STBTT_fabs(dy))
dy6 = -dy;
else
dx6 = -dx;
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
break;
default:
return STBTT__CSERR("unimplemented");
}
} break;
default:
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
return STBTT__CSERR("reserved operator");
if (b0 == 255) {
f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
} else {
stbtt__buf_skip(&b, -1);
f = (float)(stbtt_int16)stbtt__cff_int(&b);
}
if (sp >= 48) return STBTT__CSERR("push stack overflow");
s[sp++] = f;
clear_stack = 0;
break;
}
if (clear_stack) sp = 0;
}
return STBTT__CSERR("no endchar");
#undef STBTT__CSERR
}
I laugh so I don't cry.
Real programmers use butterflies
|
|
|
|
|
I either write code analysis report, where I divide code into sections and write section by section, what I think it does, then verify with debugger, or I create a good old flow diagram, if it is really cryptic (even for OO this will work for extracting actual algorithms, if you can identify sequence first).
|
|
|
|
|
I can totally see the sense in that, but I could never do it. Too rigorous for me.
I am good at improvisation and creativity, but I am no good at being methodical.
Real programmers use butterflies
|
|
|
|
|
Yeah, it is exhausting to do in a complex code base.
|
|
|
|
|
Not exactly. I used to use C to spit out ARM16 Assembler so I got an idea how I could program what I needed in assembler...then I yanked out all the stuff I didn't need (Like when you throw out all the useless HTML an editor generates). Smaller, faster, optimized and straight to the point (well for me...anybody else would also have to be comfortable with ARM16 as well)
|
|
|
|
|
I rarely write in assembly these days but I read it a lot. I've focused more on getting C and particularly C++ to generate the exact machine code I intended if I'd have written by hand, or as is often the case, better.
Real programmers use butterflies
|
|
|
|
|
Do you port all pointers to array access?
Pointers are always the pain for this type of exercise. Some algorithms are easier to understand that way. Multilevel pointers are the worst.
|
|
|
|
|
Whenever I can, that's what I do. I turn it to arrays and indices. It is difficult but actually that process is critical for me to understand it. It's one of the most important parts of the port.
And yeah, double indirection and such gets tricky fast.
Real programmers use butterflies
|
|
|
|
|
Start by determining what data it works with. Then split out the functions and start figuring out the inputs and outputs from each function. Finally, make a process and data flow diagrams for the code. This process makes short work of understanding even the most cryptic code.
If you don't want to spend a day or two doing this process there are tools like sourcetrail that will do the work for you.
|
|
|
|
|
If the project is fairly significant in size with multiple .c and .h files with many functions, I will often turn doxygen (with graphviz) loose on it. Even though the code may not have any doxygen tags or doxygen-compatible comment blocks to generate function and API documentation, it can still give you an idea of "what calls what" in a graphical context.
|
|
|
|
|
My understanding of ranked voting is that a voter puts down his choices as an ordered set, and for the first round, the #1 votes are tallied; if no one has 50%+1, then the lowest vote-getter gets discarded, and everyone who had him as #1 simply have everyone else move up a place, and the process repeats.
As long as there aren't too many candidates - and indeed, there is hardly ever more than 6 candidates who get more than 2% of the vote - than a complete list pertaining to the permutations of the candidates could be released, and done so as they are counted, like a canonical election. I use the number 6 because 6! - 720 is still a digestible number. In fact, the law could be written so only that the first round eliminates everyone outside of the top-6.
For example, using this 6 number, the state's Secretary of State could release the vote total of every permutation of the 6, and election-nerds like the gang at 538.com or the NY Times' (infamous) needle could crank the numbers as they see fit trying to put out the probabilities for the 6 at that instance.
|
|
|
|
|
how is it possible to discuss political elections without getting political?
|
|
|
|
|
There are different ways of implementing Ranked Voting.
Ranked voting - Wikipedia
"Time flies like an arrow. Fruit flies like a banana."
|
|
|
|
|
Ranking all (or all-minus-one) options would be tedious if there were many.
I imagine that "ranking your top three" would simplify things considerably when there are a lot of options from which to choose.
Maybe something like "top three or the SQRT of the number of options" would suffice?
|
|
|
|
|
If we use bit groupings for the ranks of each candidate, that would look something like:
Bits per candidate: floor(log_2(candidateCount)) + 1
Bits per vote: candidateCount * bitsPerCandidate
Total space for election: voters * bitsPerVote
So given 300,000,000 voters with 12 candidates:
space = 300,000,000 * 12 * (floor(log_2(12)) + 1)
space = 14,400,000,000 bits or 1.8 GB
Given the same amount of voters with 24 candidates:
space = 300,000,000 * 24 * (floor(log_2(24)) + 1)
space = 36,000,000,000 bits or 4.5 GB
Space definitely isn't the issue. What about the algorithm?
1) Bin every vote by first-pick candidate.
2) If no bin is >50% of the votes, re-bin the lowest bin and repeat #2.
3) The >50% bin is your winner.
I honestly don't see why this would be an issue. Worst case scenario something like v+(c-2)*(v/2) run-time where v is the vote count and c is the number of candidates. v/2 is just a napkin-math average since the redistributed bins would start out small and grow as the candidate list got shorter.
Again, just a bunch of napkin math so I probably missed something but I never bought the "it's too hard to compute" excuse either And I'm sure there are clever tricks to reduce the time required.
EDIT: For reference, if processing a vote takes:
1 microsecond: 30 minutes to determine a winner @ 300M votes, 12 candidates
1 millisecond: 20 days, 20 hours to determine a winner @ 300M votes, 12 candidates
And this is a single-threaded, un-optimized, brute-force approach.
modified 6-Jul-21 21:48pm.
|
|
|
|
|