Posts for Bisqwit


Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Nach wrote:
Bisqwit wrote:
"Any being which it is right to call God must want there to be as little suffering in the word as is possible."
Citation needed. Why would you assume that?
For clarity, the quote was from the questionaire I was responding to. As for my opinion, in my post, I did not either explicitly or implicitly indicate how I answered to that claim. So I can only assume that your question is not addressed to me.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Regarding other authors' movies submitted; the very first submission on this site was Morimoto's SMB3 ― and he sure did not submit it. (The first one published was Morimoto's Mega Man 2. Same dilemma.)
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
GMan wrote:
I also found this interesting quiz I think would be interesting for everyone to take, regardless of your religion. Sorry if it's been mentioned before.
I found myself having problems trying to parse the grammar of the claim "Any being which it is right to call God must be free to do anything." The problem hindered me of providing a meaningful answer, so I chose randomly. The same problem occurred in the very next claim, as well. That claim was: "Any being which it is right to call God must want there to be as little suffering in the word as is possible." After reading it three times, I understood the grammar in this and the previous question. But now I don't understand what they mean by "in the word". So another random answer. The rest of the questions were clearer; however, a bit too black-and-white for my tastes. So I had to work with what I was given. I got my first "hit" in claim 13. I disagree. I had indeed claimed that it is justifiable to base one's beliefs on something not absolutely proven, but I also agreed that it is foolish. Both can be true simultaneously: People have the freedom; they can believe in anything they want. And sometimes, even strong beliefs turn false, or vice versa. For example, in juristical matters -- it has happened that someone's innocence is proven only decades later. But in the same time, people can judge you foolish. If you are tired of trying to refute those claims, you can just accept that people think of you as foolish. As I do. The same goes with claim 14, which also gave me a "hit". After that, so did everything else, because I was no longer confident about the parameters of the questionare :) In the end, "You suffered 3 direct hits and bit 2 bullets."
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
pirate_sephiroth wrote:
You say that because you didn't see nineko's tribute to our new admin.
Now you're correct, in that I did not see such thing. Poor lad Nineko. Whatever happened to him? Hmm, this might be off-topic.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
pirate_sephiroth wrote:
Bisqwit can't overcome this temptation of overcoming temptations...
Incorrect, I just overcame the temptation of overcoming the temptation of posting a reply to refute your incorrect statement! _______________ A little redundancy never hurts. Now I'm reminded of clanging.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
This is the only time ever that I've felt a temptation of posting a reply consisting solely of a certain overused picture here at these boards. But quickly, I overcame the temptation and instead, posted this text block that is of roughly the same shape as that particular image. (At least when printed in the default proportional font.)
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
It's even better in 64-bit: (Irrelevant lines omitted)
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string " is" 
.LC1:
        .string " is not"
.LC2:
        .string "%d%s.\n" 
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
        subq    $8, %rsp
        movq    8(%rsi), %rdi
        movl    $10, %edx
        xorl    %esi, %esi
        call    strtol
        cmpl    $63, %eax
        movl    %eax, %esi
        jbe     .L11
.L8:
        movl    $.LC1, %ecx
.L9:
        movq    %rcx, %rdx
        movl    $.LC2, %edi
        xorl    %eax, %eax
        addq    $8, %rsp
        jmp     printf
        .p2align 4,,10
        .p2align 3
.L11:
        movl    %eax, %ecx
        movl    $1, %eax
        movabsq $2891462833508853932, %rdx
        andl    $63, %ecx
        salq    %cl, %rax
        movl    $.LC0, %ecx
        testq   %rdx, %rax
        jne     .L9   
        jmp     .L8
That's awfully small code for such complex looking program. The method of comparing to the list of prime numbers is by checking the given number against a single bitmask. This demonstrates well the fact that abstraction in C++ does not necessarily reflect runtime overhead. There are zero method calls or pointers in this assembler code, even though the C++ code was rife with functors and references.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Warp wrote:
And since we are in the topic of "guess what this program does", the next question would be: Which encoding does the following function perform (function name obfuscated so that it won't give the answer right away):
void foo(const unsigned char* begin, const unsigned char* end, std::string& dest)
{
    while(begin < end)
    {
        unsigned value = 0;
        char buf[6] = { 'z', 0, 0, 0, 0, 0 };
        for(int i = 0; i < 4; ++i, ++begin)
            value = value << 8 | (begin<end ? *begin : 0);
        if(value || begin > end)
            for(int i = 0; i < 5; ++i, value/=85) buf[4-i] = value%85+33;
        dest += buf;
    }
    if(begin > end) dest.resize(dest.size()-(begin-end));
}
Well, since it contains the magic number 85 and seems to be about encoding numeric values into a buffer, and it reminds me of a similar encoding scheme encountered in either PDF or FLV files, I don't remember which, I had to check. I did a locate base85, and found a file in Git's source code that does something like that. I'm satisfied with that hypothesis. The rest of the code seems to be about encoding the length of the string in the buffer, so a decoder knows how long a string to decode, assuming lack of that information from other sources. So in short, the answer to your question is: Ascii85.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
arflech wrote:
Anyway, yesterday I used an Ubuntu machine to compile that Chrono Trigger-related C code (after compiling TCC and then using TCC to compile TCC), and the program still didn't seem to do anything.
While running, it is to be accessed with another program. A program commonly utilized in Internet-capable computers.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Warp wrote:
For example, I consider this to be an acceptable usage:
bool Point::operator<(const Point& rhs) const
{
    return x != rhs.x ? x < rhs.x : y != rhs.y ? y < rhs.y : z < rhs.z;
}
I prefer to write code like that like this:
bool Point::operator< (const Point& rhs) const
{
    if(x != rhs.x) return x < rhs.x;
    if(y != rhs.y) return y < rhs.y;
    if(z != rhs.z) return z < rhs.z;
    return false;
}
The good thing about this approach is that it can be extended as the number of members grows without the code becoming unsightly. It can naturally be shortened as:
bool Point::operator< (const Point& rhs) const
{
    if(x != rhs.x) return x < rhs.x;
    if(y != rhs.y) return y < rhs.y;
    return z < rhs.z;
}
EDIT: Oh look at that, I missed the fact that your Points were 3D at first reading. Case in a point. Pun coincidental.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Bisqwit wrote:
I am surprised as well, how simple turns out to be the PNG format, and the code that generates a valid PNG file (albeit without using fancy huffman coding, but valid nevertheless).
In comparison, GIF turns out to be really complicated. I had to make a GIF writer for a project at work, and even though this code, similarly to the PNG writer I posted, does the least necessary work to produce legal "compressed" stream, it is considerably lengthier than the PNG writer. * (This is a simplified version of the code I wrote for work; the actual version creates an animated GIF. I also wrote the actual code in C++; this sample is in C.) [code c]static void WriteGIF89a( FILE* fp, unsigned width, unsigned height, const unsigned char* data) { unsigned palette_extra = 64-n_palette_colors; /* assuming 32<n<=64 */ const unsigned framesize = width * height; const unsigned char GifHdr[] = { 'G','I','F','8','9','a', width&0xFF, width>>8, height&0xFF, height>>8, 0x80 | // global color table (palette) ((8-1)*16) | // 8-bit colors (0*8) | // palette is not sorted (6-1), // 64 colors (2^6) n_palette_colors-2, // background color index 0 // dummy aspect ratio }; const unsigned char ImageDescriptor[] = { 0x2C, 0,0,0,0, // left,top position width&0xFF, width>>8, height&0xFF, height>>8, 0 }; fwrite(GifHdr, sizeof(GifHdr), 1, fp); fwrite(&palette[0], n_palette_colors*3, 1, fp); fwrite(&palette[0], palette_extra *3, 1, fp); fwrite(ImageDescriptor, sizeof(ImageDescriptor), 1, fp); { unsigned char minbits = 6; /* 6 bits are enough to convey image pixels */ unsigned codebits = minbits+1, clrcode = 1 << minbits, eoicode = clrcode+1; unsigned pos, bumppos, outcode = clrcode, bufbits = 0, n_bufbits = 0; unsigned char buffer[256] = {0}; #define buflen buffer[0] fputc(minbits, fp); for(pos=0; ; ) /* This code copied and adapted from ungifwrt in gifsicle */ { bufbits |= outcode << n_bufbits; for(n_bufbits += codebits; n_bufbits >= 8; n_bufbits -= 8) { buffer[1 + buflen++] = bufbits & 0xFF; if(buflen >= 255) { fwrite(buffer,buflen+1,1,fp); buflen=0; } bufbits >>= 8; } if(outcode == clrcode) { bumppos = pos + (clrcode - 2); } else if(pos == bumppos) { outcode = clrcode; continue; } else if(outcode == eoicode) { break; } outcode = (pos < framesize) ? data[pos++] & ((1 << minbits)-1) : eoicode; } if(n_bufbits) buffer[1 + buflen++] = bufbits; if(buflen > 0) fwrite(buffer,buflen+1,1,fp); #undef buflen fputc(0, fp); } fputc(0x3B, fp); }[/code] *) Or so I wanted to claim, but turns that after I removed the animation handling code, it is about the same length as the PNG writer. Oops.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Warp wrote:
int foo = 1 + probablyTrueBoolean;
;)
Taking hint from the probable values, for greater documentation value, I would rather write it as
int foo = 2 - !probablyTrueBoolean;
... if I were so inclined. Not to negate anything Nach said.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Nach wrote:
Well I thought it was obvious for the most part, with good function names and clear strings which says what it does. <...> What I do find very enlightening about your mini program is that it has a PNG encoder. I never considered doing that without using libpng.
Thank you for humoring me. Some 20 edits later, I have to admit that I am surprised as well, how simple turns out to be the PNG format, and the code that generates a valid PNG file (albeit without using fancy huffman coding, but valid nevertheless). arflech, the biggest problem in porting that code to Winsock is the use of fdopen(). In POSIX, all file descriptors are equal, and they can all be used with the same system calls. In Microsoft Windows, sockets live in an entirely different universe than file handles, and a function that can read from a file (such as fgets, in this case) cannot read from a socket.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
GMan wrote:
EDIT: wtf? I can't put "T" after "typename".
It's not because of "typename", but because you're telling phpBB you are posting HTML. Stop claiming you're posting HTML, and it will stop making assumptions on your <s and >s.
arflech wrote:
Windows uses a slightly different implementation of sockets.
I know. Maybe I should have been more explicit, but I never claimed to have implemented Microsoft Winsock support; only POSIX standard. Which is supported by Cygwin.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
DeFender1031 wrote:
Now i have one:
Too well-known. Only that you've made it into a template function. ;) No takers for my program? It contains education in small size about a number of popular standards, about Chrono Trigger, and about one particular feature of WWW that is very rarely used.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Nach wrote:
x&UINT32_C(037777777776)
That's the most complex way of saying x > 1 that I have ever seen... Not that the rest of the function is much better. ;) You could have at least said x & ~unsigned(1) and replaced the awkward uint32_t types with unsigned int.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Since people like to analyze source code… What does this do?
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* for inet_ntoa */
#include <string.h> /* for memcpy */
#include <stdio.h> /* for fwrite etc, fdopen */
#include <unistd.h> /* for usleep */
#include <signal.h>

/* Data is PCX image with header (128 bytes) and redundant palette entries
 * stripped, RLE and padding undone, further compressed using a custom
 * RLE scheme */
static const unsigned char compdata[] =
"fe@@LNceMAAme@@LNceMAAje@@LNceMAAke@U^@NLMAMA^`bMMje@U^@NLMAMA^`bMMge@U^@NLM"
"AMA^`bMMje@^LNLeMG`bMje@^LNLeMG`bMge@^LNLeMG`bMie@UHNLL@Ub^`bMG`bie@UHNLL@Ub"
"^`bMG`bfe@UHNLL@Ub^`bMG`bie@^H@^Ub^bM`bG^ie@^H@^Ub^bM`bG^fe@^H@^Ub^bM`bG^ie@"
"KH@U^UU^M`bMG^je@KH@U^UU^M`bMG^ge@KH@U^UU^M`bMG^je@K@@UU^UUMM`b^Bje@K@@UU^UU"
"MM`b^Bge@K@@UU^UUMM`b^Bje@UHG@^^MD^AJ`bDje@UHG@^^MD^AJ`bDge@UHG@^^MD^AJ`bDie"
"@H_@G`e@H^WWVP``Cje@^HG`e@H^WWVP``Cge@K@G`e@H^WWVP``Che@HK@Cae@H^DW`dA``Cje@"
"U@ae@H^DW`dA``CgeH_@ae@H^DW`dA``Che@__@ce@HDWb\\Cie@K@@be@HDWb\\Cge@Uce@HDWb"
"\\Cie@UU@beCICW\\\\Cie@H_@deICW\\\\Cge@K@ceCICW\\\\Cje@UH@aeCKKRCCke@K@CceIK"
"KCCieH_@beCKKXCCle@H@aeCRKKRWCje@H_@ceIKXCWChe@K@CaeCbKCWCme@beIWRRCacCie@_U"
"U@beIKXCacCfe@H_@beCKKXCacCoeCW\\\\WCbcKAge@@UH@beIXXCbcCee@_UU@aeCKXXCbcCme"
"CS\\\\DCac]]D\\Age@H@ceI\\XC`c]]Cfe@UH@aeCX`aQC`c]]CmeAHSDcCQC\\``HCge@deI`a"
"\\ICQCge@H@beC\\`abCQCmeCHHWDHHCW\\\\AIW\\CleI`a\\IW\\\\Age@ceCYHHCW\\\\AleC"
"WWHCCIAW\\Q`eCHWCleIHHQ@\\@AmeCHWWC\\QIleCIHICOdAaeCCmeIWWQX@T@meCHW`aWCXIme"
"bCOIX@T]XApeIW`aQNFPCmeICH`aWC[IpeIXNFPTXAqebIFPECmeIKcCXIpeIXFPENXAreI@PE@C"
"meIXKFPXCIpeICPEXNXAIqeCZ@RHAmeICXPXC\\IIkeCAAW\\\\WPEXA``\\CoeAHWIW\\CmeI\\"
"CQC\\`a``QIieCHHIW\\WCaeCW\\WAneCHIHIIAkeCIW\\``\\CaeC\\``\\CheCHWHDACceCWIH"
"AmeAHWIIWCjeCIWIW\\CceC\\IHACCeeCHIHIeeAIHWICCkeAHHIHCjeCbHWACdeCWHHIWWAdeAI"
"WAfeAHHIbWCkeAIWICjeAHWIHCfeAHWWHAeeAIHHIfeAHWWHHAkeCHHWWAieAIWHCgeAHWHAgejA"
"IbHAAkeAAIIHWHAieAHWHCdebAIHAceb@b`@``;bi\"H\22;HX\303H33`iP;`iPb\1b\22\205`"
"``i\375`yH\313\22P\246`i`q``\334@\324\12\225\303;\1\266\32H\324\303\32\225"  
"\22\205\375\303`y;\313\266\246\303\22\277\313H\225\344\"\256\334;b\375\266"
"\354\324\225\364\277\277\215`q\266\215\313\277\215\375\277\246\225\277\266"
"\354c\266d\277";
#define n_palette_colors 38
static unsigned char pcxdata[32*24*3 + n_palette_colors*3];
#define palette (&pcxdata[sizeof(pcxdata)-n_palette_colors*3])
static void DecodeImage()
{
    unsigned srcpos, limit=sizeof(compdata), outpos=0, d, value, e;
    for(srcpos=0; srcpos<limit; ++srcpos)
        for(d = compdata[srcpos] ^ 64, value = d,
            e = (d >= 32 && d < 64) ? (value = compdata[++srcpos] ^ 64, d-32+1) : 1;
            e-- > 0; ) pcxdata[outpos++] = value;
}
static void PutWord(char* target, unsigned dword, int msb_first)
{
    int p;
    for(p=0; p<4; ++p) target[p] = dword >> (msb_first ? 24-p*8 : p*8);
}
static unsigned chksum32(const char* data, unsigned size, unsigned res, int crc)
{
    if(size == 0) return res;
    if(!crc) { unsigned s1 = ((res & 0xFFFF) + (*data & 0xFF)) % 65521; /* adler32 */
    return chksum32(data+1, size-1, s1 + ((((res>>16) + s1) % 65521) << 16), 0); }
    return data ? chksum32(data+1,size-1, ~((~res>>8) ^ chksum32(0,8,(~res ^ *data) & 0xFF,1)), 1)
                : chksum32(0,size-1, (res>>1) ^ ((res&1) ? 0xEDB88320u : 0), 1); /* crc32 */
}
static unsigned EncodeImageData(char* target,
                                unsigned (*Compress)(char*,const char*,unsigned))
{
    static int framenumber = 0, xoffsets[4] = {0,25,47,25};
    char databuf[64*(46+1)]; /* width: 46, height: 64 */
    int frame_x = xoffsets[framenumber++ % 4], frame_y = 0, y,x;
    for(y=0; y<64; ++y)
        for(databuf[y*(46+1)]=x=0; x<46; ++x)
            databuf[y*(46+1)+1+x] = pcxdata[(frame_x+x/2) + (frame_y+y/2)*72];
    return Compress(target, databuf, sizeof(databuf));
}
static unsigned Deflate(char* target, const char* source, unsigned srcsize)
{
    /* A bare-bones deflate-compressor (as in gzip) */
    int algo=8, windowbits=8 /* 8 to 15 allowed */, flevel=0 /* 0 to 3 */;
    /* Put RFC1950 header: */
    target[0] = algo + (windowbits-8)*16;
    target[1] = flevel*64 + 31-((256*target[0])%31); /* checksum and compression level */
    /* Compress data using a lossless algorithm (RFC1951): */
    target[2] = 1;  /* bfinal bit and btype: 0=uncompressed */
    PutWord(target+3, srcsize|(~srcsize<<16), 0);
    memcpy(target+7, source, srcsize);
    /* After compressed data, put the checksum (adler-32): */
    PutWord(target+7+srcsize, chksum32(source, srcsize, 1, 0), 1);
    return srcsize + 7+4;
}
static void EncodeImage(char** target)
{
    #define AddedChunk(type,n) do { unsigned ncopy=(n); \
        memcpy(*target+4, (type), 4); \
        PutWord(*target, ncopy, 1); /* in the chunk, put crc32 of the type and data (below) */ \
        PutWord(*target + 8 + ncopy, chksum32(*target + 4, 4 + ncopy, 0, 1), 1); \
        *target += 12+ncopy; } while(0)
    memcpy(*target, "\x89PNG\15\12\x1A\12", 8); /* Put header - always const */
    *target += 8;
      PutWord(*target+8 + 0, 46, 1); /* Put image width    */
      PutWord(*target+8 + 4, 64, 1); /* and height in IHDR */
      memcpy(*target+8 + 8, "\x8\3\0\0\0", 5);
      /* Meaning of above: 8-bit,paletted,deflate,std filters,no interlacing */
    AddedChunk("IHDR", 13);
      memcpy(*target+8, palette, n_palette_colors * 3);
    AddedChunk("PLTE", n_palette_colors*3);
    AddedChunk("IDAT", EncodeImageData(*target+8, Deflate) );
    AddedChunk("IEND", 0);
    #undef AddedChunk
}
static void Serve(int sock)
{
    static const char bound[] = "qegkqpekga";
    char Buf[20000];
    signal(SIGPIPE, SIG_IGN);
    FILE* fp = fdopen(sock, "r+");
    fgets(Buf, sizeof(Buf), fp); /* Get the request */
    do {
        fgets(Buf, sizeof(Buf), fp);
        /* Read until an empty line is received */
    } while(*Buf != '\n' && *Buf != '\r');
    fprintf(fp,
       "HTTP/1.0 200 OK\n"
        "Content-type: multipart/x-mixed-replace; boundary=\"%s\"\r\n"
        "\r\n", bound);
    printf("Connection received\n");
    for(;;)
    {
        char* EndPtr = Buf;
        EncodeImage(&EndPtr);
        if(fprintf(fp,
            "--%s\n"
            "Content-type: image/png\r\n"
            "Content-disposition: inline\r\n"
            "Content-length: %lu\r\n"
            "\r\n", bound, (unsigned long)(EndPtr-Buf)) <= 0
        || fwrite(Buf, EndPtr-Buf, 1, fp) < 1) break;
        if(fflush(fp) != 0) break;
        usleep(200000);
    }
    printf("Connection closed\n");
    fclose(fp);
}
int main()
{
    struct sockaddr_in MyAddr, They;
    int Plug = socket(AF_INET, SOCK_STREAM, 0), AddrLen = sizeof(They), Port = 8800;
    if(Plug < 0) { perror("socket"); return -1; }
    DecodeImage();
    memset(&MyAddr,0,sizeof(MyAddr));
    MyAddr.sin_port = htons(Port);
    MyAddr.sin_family = AF_INET;
    MyAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    { int tmp=1; setsockopt(Plug, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)); }
    if(bind(Plug, (struct sockaddr*)&MyAddr, sizeof(struct sockaddr)) < 0)
       { perror("bind"); return -1; }
    if(listen(Plug, 10) < 0)
       { perror("listen"); return -1; }
    for(;;)
    {
        int Sock = accept(Plug, (struct sockaddr*)&They, (unsigned*)&AddrLen);
        if(Sock < 0) { perror("accept"); sleep(1); continue; }
        Serve(Sock);
        close(Sock);
    }
    return 0;
}
(Tested, compiles and runs on at least Linux and Cygwin.) EDIT: Updated to use Chrono Trigger's data compression algorithm to reduce the size of the literal array embedded in the source. EDIT: Optimized data array for source code size. EDIT: Undid compression and used xor-by-64 and custom RLE instead. Also now using recursive crc32() and adler32() checksum functions…
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
In more seriousness, in my opinion, real programmers do what is necessary to get the task accomplished in an elegant manner and no more. Elegance is defined by a number of meters, such as the ratio of "accomplishes" to "does" in the code (this is my favourite) and its ease to be understood at glance. To understand the ratio of "accomplishes" to "does" in the code, consider these two examples (C):
int main() { putchar('H'); putchar('e'); putchar('l'); putchar('l'); putchar('o'); return 0; }
int main() { printf("Hello"); return 0; }
It is clear that the second code accomplishes the same as the first code but with less do'ing. It is also easier to understand at glance. A better, real world example (paraphrased from Nach's article that partially addresses this same topic):
/* Log on mondays, wednesdays and fridays.
 * dayOfTheWeek is 0-6, with 0 signifying sunday. */
void logEveryOtherDay(int dayOfTheWeek)
{
  if (dayOfTheWeek == 1)
  {
    logOpen();
    logWrite("-------------");
    logWrite("Monday");
    logData();
    logClose();
  }
  else if (dayOfTheWeek == 3)
  {
    logOpen();
    logWrite("---------------");
    logWrite("Wednesday");
    logData();
    logClose();
  }
  else if (dayOfTheWeek == 5)
  {
    logOpen();
    logWrite("------------");
    logWrite("Friday");
    logData();
    logClose();
  }
}
Changed like this, the code accomplishes more by doing less, while being also less error-prone:
static const char* const daysOfTheWeek[7] =
{ "Sunday", "Monday", "Tuesday", "Wednesday",
  "Thurday", "Friday", "Saturday" };
void logEveryOtherDay(int dayOfTheWeek)
{
  if (dayOfTheWeek % 2 != 0) /* Do logging on odd days only */
  {
    logOpen();
    logWrite("-------------");
    logWrite(daysOfTheWeek[dayOfTheWeek]);
    logData();
    logClose();
  }
}
This attitude naturally reflects the thinking of the person, and thus, it carries to daily activities as well. While this is sometimes a blessing, it is also a curse: it makes a programmer rather bad at following instructions, because they become easily distracted in trying to see patterns and in trying to optimize the instructions for lesser actions, or to eliminate the need for the actions alltogether. :) At least that applies to me.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Generally speaking, I don't buy games. I have only ever made an exception once: When Valve's Portal became available, I registered at Steam and bought the package of games that included Portal, everything from the Half-Life series so far and a few other games, because the deal met my gaming interests rather perfectly at the time. Anything else, I've either loaned (when it's a physical media such as a game cartridge), copied (when it's a DOS-era PC game) or downloaded (when it's an emulatable console game, which in my opinion counts almost as second-hand). It's not that I think that game piracy is allright; it's just because I'm not an active game consumer.
pirate_sephiroth wrote:
I only spend money on a game it is epic good in any way. For example some epic music could do that.
In this rare incident, I agree with your taste and like it.
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Warp wrote:
<...> the "std::" prefixes actually make the code easier to read, not harder. For example, suppose you have a line of code like this:
search(i1, e1, i2, e2);
Is that calling some local function, perhaps some member function of the current class, a function defined in some of the header files included in this file, or maybe a function in the standard library? It's impossible to say from that line alone. However, suppose the line was written as:
std::search(i1, e1, i2, e2);
Now there isn't even a shadow of a doubt what this function is: A function in the C++ standard library.
In my opinion, the same rationale could be used to justify putting an explicit this-> before all references to the current class's methods and properties, such as:
this->copy(this->elem1, this->elem2);
Or perhaps:
this->myClass::copy(this->myClass::elem1, this->myClass::elem2);
We all just have to draw the line somewhere(Note: I do use std:: prefixes in my code, but I try to write my code such as to avoid scattering them throughout, especially from having many on the same line.)
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Congratulations to those appointed. I'm glad to see how things go here now that Adelikat is in the helms :)
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Warp wrote:
Playing with bytecode interpreters, eh?-)
Playing with method pointers, too. This was mildly unrelated to fparser. A pointless exercise.
Post subject: Bytecodemachinehelloworldwithanarrayofconstfunctionpointers
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Bisqwit wrote:
Again a pointless exercise at various topics. Thoughtfodder. Language: C++
Equivalent code in ANSI C.
#include <stdio.h>
#include <stdlib.h>
enum { opPush, opCopy, opSwap, opPutchar, opSub,
       opJumpIfNonZero, opGosub, opReturn, nOpcodes };
typedef struct Stack
{
    int L/*limit*/,*P/*pointer*/,C/*cap*/;
} Stack;
static void push(Stack* S, int v)
  { if(S->L >= S->C)
        S->P = (int *) realloc(S->P, (S->C = (S->C + 1) * 2) * sizeof( *S->P ));
    S->P[S->L++] = v; }
static int* at(Stack* S, int v) { return &S->P[S->L - 1 - v]; }
static void dispose(Stack* S) { if(S->P) free(S->P); S->L=S->C=0; S->P=(int*)0; }
static int pop(Stack* S) { return S->P[--S->L]; }
static void copy(Stack* S, const int b[], int*ip)  { push(S,*at(S,pop(S))); b=b; ip=ip; }
static void swap(Stack* S, const int b[], int*ip)  { int *a=at(S,pop(S)), c=*at(S,0); *at(S,0)=*a; *a=c; b=b; ip=ip; }
static void sub(Stack* S, const int b[], int*ip)   { int a = pop(S); *at(S,0) -= a; b=b; ip=ip; }
static void jz(Stack* S, const int b[],int*ip)     { int v = b[++*ip]; if(pop(S) != 0) *ip = v-1; }
static void outc(Stack* S, const int b[], int*ip)  { putchar(pop(S)); b=b; ip=ip; }
static void put(Stack* S, const int b[],int*ip)    { push(S,b[++*ip]); }
static void gosub(Stack* S, const int b[],int*ip)  { push(S,*ip+2); *ip = b[*ip+1]-1; }
static void ret(Stack* S, const int b[], int*ip)   { *ip = pop(S)-1; b=b; }
static void (*const opcodes[nOpcodes]) (Stack* S, const int b[], int*ip) =
{ put,copy,swap,outc,sub,jz,gosub,ret };

int main(void)
{
    static const int code[] =
    {
        opPush, 'H',  /* 0 */
        opPush, 'e',  /* 2 */
        opPush, 'l',  /* 4 */
        opPush, 'l',  /* 6 */
        opPush, 'o',  /* 8 */
        opPush, 5,    /* 10 - length of string */
        opGosub, 40,   /* 12 */
        opPush, ',',  /* 14 */
        opPush, ' ',  /* 16 */
        opPush, 'w',  /* 18 */
        opPush, 'o',  /* 20 */
        opPush, 'r',  /* 22 */
        opPush, 'l',  /* 24 */
        opPush, 'd',  /* 26 */
        opPush, '.',  /* 28 */
        opPush, 8,   /* 30 - length of string */
        opGosub, 40,  /* 32 */
        opPush, '\n', opPutchar, /* 34 */
        opPush, -1, opReturn, /* 37 - end */
        opPush, 1, opSwap, /* 40 */
        opPush, 0, opCopy,
        opPush, 0, opCopy,
        opPush, -2, opSub,
        opSwap, opPutchar,
        opPush, 1, opSub,
        opPush, 0, opCopy,
        opJumpIfNonZero, 43,
        opPush, 1, opSwap,
        opReturn
    };
    Stack S = {0, (int*)0, 0 };
    int ip;
    for(ip=0; ip>=0; ip += 1)
        opcodes[code[ip]](&S, code, &ip);
    dispose(&S);
    return 0;
}
This is probably faster than the C++ code above, because this uses function pointers rather than method pointers. Method pointers have to support virtual functions as well. A C++ version without method pointers, without looking like the C code, could be like this:
#include <vector>
#include <iostream>
enum { opPush, opCopy, opSwap, opPutchar, opSub,
       opJumpIfNonZero, opGosub, opReturn, nOpcodes };
class Interpreter
{
private:
    std::vector<int> S;
    int& at(int v) { return S[S.size() - 1 - v]; }
    int pop() { int ret = at(0); S.pop_back(); return ret; }
public:
    void Iterate(const int code[], int& ip)
    {
        int a,*c;
        switch(code[ip])
        {
        case opPush:          S.push_back(code[++ip]); break;
        case opCopy:          S.push_back(at(pop())); break; 
        case opSwap:          c=&at(pop()); a=at(0); at(0)=*c; *c=a; break;
        case opPutchar:       std::cout << char(pop()); break;
        case opSub:           a = pop(); at(0) -= a; break;   
        case opJumpIfNonZero: a = code[++ip]; if(pop() != 0) ip = a-1; break;
        case opGosub:         S.push_back(ip+2); ip = code[ip+1]-1; break;   
        case opReturn:        ip = pop()-1; break;
}   }   };
int main()
{
    static const int code[] =
    {
        /* same as above, omitted */
    };
    Interpreter machine;
    for(int ip=0; ip>=0; ip += 1)
        machine.Iterate(code, ip);
}
Post subject: Bytecodemachinehelloworldwithanarrayofconstmethodpointers
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Again a pointless exercise at various topics. Thoughtfodder. Language: C++
#include <vector>
#include <iostream>
enum { opPush, opCopy, opSwap, opPutchar, opSub,
       opJumpIfNonZero, opGosub, opReturn, nOpcodes };
class Interpreter
{
public:
    static void (Interpreter::*const opcodes[nOpcodes]) (const int[], int&);
private:
    void copy(const int[], int&)       { S.push_back(at(pop())); }
    void swap(const int[], int&)       { int &a=at(pop()), b=at(0); at(0)=a; a=b; }
    void sub(const int[], int&)        { int a = pop(); at(0) -= a; }
    void jz(const int b[],int& ip)     { int v = b[++ip]; if(pop() != 0) ip = v-1; }
    void putchar(const int[], int&)    { std::cout << char(pop()); }
    void push(const int b[],int& ip)   { S.push_back(b[++ip]); }
    void gosub(const int b[],int& ip)  { S.push_back(ip+2); ip = b[ip+1]-1; }
    void ret(const int[], int& ip)     { ip = pop()-1; }
    int& at(int v) { return S[S.size() - 1 - v]; }
    int pop() { int ret = at(0); S.pop_back(); return ret; }
    std::vector<int> S;
};

void (Interpreter::*const Interpreter::opcodes[nOpcodes]) (const int[], int&) =
{
    &Interpreter::push, &Interpreter::copy, &Interpreter::swap,
    &Interpreter::putchar, &Interpreter::sub, &Interpreter::jz,
    &Interpreter::gosub, &Interpreter::ret
};

int main()
{
    static const int code[] =
    {
        opPush, 'H',  // 0
        opPush, 'e',  // 2
        opPush, 'l',  // 4
        opPush, 'l',  // 6
        opPush, 'o',  // 8
        opPush, 5,    // 10 - length of string
        opGosub, 40,   // 12
        opPush, ',',  // 14
        opPush, ' ',  // 16
        opPush, 'w',  // 18
        opPush, 'o',  // 20
        opPush, 'r',  // 22
        opPush, 'l',  // 24
        opPush, 'd',  // 26
        opPush, '.',  // 28
        opPush, 8,   // 30 - length of string
        opGosub, 40,  // 32
        opPush, '\n', opPutchar, // 34
        opPush, -1, opReturn, // 37 - end
        opPush, 1, opSwap, // 40
        opPush, 0, opCopy,
        opPush, 0, opCopy,
        opPush, -2, opSub,
        opSwap, opPutchar,
        opPush, 1, opSub,
        opPush, 0, opCopy,
        opJumpIfNonZero, 43,
        opPush, 1, opSwap,
        opReturn
    };
    Interpreter machine;
    for(int ip=0; ip>=0; ip += 1)
        (machine.*Interpreter::opcodes[code[ip]])(code, ip);
}
Rather than spoil the presentation of the program with long blobs of comments, I'll just explain the curious lines here separately:
    static void (Interpreter::*const opcodes[nOpcodes]) (const int[], int&);
    // ^   ^     ^^^^^^^^^^^^^^      ^      ^ an array   ^^^^^^^^^^^^^^^^^
    // ^   ^     ^                   ^ called "opcodes"                 ^
    // ^   ^     ^ consists of pointers to methods of class Interpreter ^
    // ^   ^ returning nothing (void)                                   ^
    // ^                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ^                            ^ and they take these parameters
    // ^^ rather than a per-instance property, the array
    //    is shared to all instances of class Interpreter
void (Interpreter::*const Interpreter::opcodes[nOpcodes]) (const int[], int&) =
// ^  ^^^^^^^^^^^^^^      ^            ^      ^ an array     ^
// ^  ^                   ^            ^ called "opcodes"    ^
// ^  ^                   ^ within class Interpreter         ^
// ^  ^ consists of pointers to methods of class Interpreter ^
// ^ returning nothing (void)                                ^ taking these
//                                                             parameters
// is initialized to this list:
{
    // Repeating "&Interpreter::" sucks in the array definition,
    // but here is what happens, if one tries to do without (gcc 4.4):
    //  ret: error: argument of type 'void (Interpreter::)(const int*, int&)' does not match 'void (Interpreter::* const)(const int*, int&)'
    // &ret: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&Interpreter::ret'
        (machine.*Interpreter::opcodes[code[ip]])(code, ip);
        // ^      ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^   ^^^^^^^^
        // ^      ^                     ^ array index ^
        // ^      ^ Access the method pointer table   ^
        // ^                                          ^
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // ^ Call the member function using the instance in "machine"
Editor, Experienced Forum User, Published Author, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
t3h Icy wrote:
Mothrayas wrote:
RT-55J wrote:
<...> MM1<...>
<...> pause trick allowing us to kill any boss with 1 ammo.
It doesn't work quite like that<...>
Yeah, Gutsman for instance still doesn't quite die with just one bullet. Mildly entertaining to try, though.