switch + goto (bzw. utf8)



  • was machen null_first_three_bits und so? den code müßte ich erst entoptimieren.



  • der ist 0 optimiert, sondern erst mal nur so geschrieben, dass er läuft und verständlich ist...

    was machen null_first_three_bits und so?

    3mal darfst du raten ;o)

    es setzt die ersten 3 bit auf 0

    static unsigned char null_first_three_bits(unsigned char value)
    {// 0001 1111
    	return value & 0x1F;
    }
    

    Der Rest analog dazu... (ich find nur ein tmp & 0x1F so extrem nichtssagend deshalb verfrachte ich so was immer in extra fkt - wenn man binäre schreiben könnte und nicht nur hexadezimal wär das scho cool...)
    ucs4 ist nen typedef auf unsigned long

    das wars eigtl, oder?

    bb



  • unskilled schrieb:

    es setzt die ersten 3 bit auf 0

    static unsigned char null_first_three_bits(unsigned char value)
    {// 0001 1111
    	return value & 0x1F;
    }
    

    Der Rest analog dazu... (ich find nur ein tmp & 0x1F so extrem nichtssagend deshalb verfrachte ich so was immer in extra fkt

    Aha.
    Also wirds zu

    template <typename InputIterator>
    static ucs4 get_ucs4_from_utf8(InputIterator &iter, InputIterator end)
    {
    	unsigned char tmp = unsigned char(*iter++);
    	const unsigned char length = get_length(tmp);
    
    	if (length==0)
    		return ucs4(tmp);
    
    	tmp = tmp & (0xef>>length);
    
    	ucs4 to_add = make_byte(tmp, --length);
    
    	for (; length >= 0; --length)
    	{
    		if (iter == end)
    			throw std::runtime_error("wrong utf8 encoding");
    		to_add = add(to_add, *iter++, length);
    	}
    
    	return to_add;
    }
    

    (ungetestet)



  • ich hasse ja eigtl so nen bit-gefrickel in meinem quellcode...^^

    aber die idee hier
    tmp = tmp & (0xef>>length);
    ist klasse - danke! : >

    die schleife am ende würdest du lassen?!
    oder durch nen switch ersetzen?
    oder was ganz anderes?

    bb



  • unskilled schrieb:

    ich hasse ja eigtl so nen bit-gefrickel in meinem quellcode...^^

    aber die idee hier
    tmp = tmp & (0xef>>length);
    ist klasse - danke! : >

    die schleife am ende würdest du lassen?!
    oder durch nen switch ersetzen?
    oder was ganz anderes?

    bb

    ja und nein.
    ich hab mal ganz neu angesetzt und die fehlerprüfing rausgemacht.
    (bitte nicht erschrecken!)

    template <typename InputIterator>
    static ucs4 get_ucs4_from_utf8(InputIterator &iter, InputIterator end)
    {
    	ucs4 result=*iter++;
    	if(result>128)
    		return result;
              maske<<=1;
    	result=(result<<6)|(*iter++&0x5f);
    	if(result&maske) return result&...;
              maske<<=1;
    	result=(result<<6)|(*iter++&0x5f);
    	if(result&maske) return result&...;
              maske<<=1;
    	result=(result<<6)|(*iter++&0x5f);
    	return result&maske;
    }
    

    Das sieht danach aus, als könnte man ne schleife draus machen. und dann wieder mit der fehlerprüfung rein.
    und zur größten not könnte man die masken so schreiben

    const ucs4 B32_00000000_00000000_00000000_00001111=0x0000000f;
    const unsigned char B8_011111111=127;
    

    oder vielleicht leckerer keine schleife aber immer

    if(iter==end) goto fehler
    

    um den throw-code nur einmal zu haben. klingt schnell und nicht zu kompliziert. dann ich nicht mehr das doofe maske<<=1.



  • unskilled schrieb:

    while ist auch komplett sinnlos, oder?

    Ich sehe ich habe es mit einem Liebhaber des "switch" Konstrukts zu tun. "switch" ist vorallem in C sinnvoll, da es dort häufig notwendig ist, Integer als Typid zu benutzen, und manuell Dispatching nachbauen muß. Das entfällt in sauberem C++ komplett. Es bleiben wenige Fälle übrig in denen es sinnvoll ist, in C++ switch zu verwenden. Genauso wenig kann man auf "goto" immer verzichten, das Verlassen mehrfach verschachtelter schleifen ist sonst zu umständlich. Aber das dürfte eine der wenigen sinnvollen Anwendungsfälle sein.

    Im konkreten Fall ist switch definitiv nicht sinnvoll. Die vielen "goto"s sind mehr als deutlich ein Hinweis auf schlechtes Design.

    P.S. Wenn man schon ein Schleifenkonstrukt abschaffen will, weil es nicht orthogonal zu anderen Sprachkonstrukten ist, dann nimmt man besser die "for"-Schleife: siehe Oberon.



  • @volkard - uff, darüber schlaf ich erst mal ne nacht 😉 danke 🙂

    bb



  • Ich hab deinen Quellcode mal ein wenig vergewaltigt:

    template <typename InputIterator>
    static ucs4 get_ucs4_from_utf8(InputIterator &iter, InputIterator end)
    {
    	ucs4 result = ucs4(*iter++);
    	if(result < 128)
    		return result; //standard ascii character
    	if(!(result & 64))
    		goto error; //10xx xxxx
    
    	if(iter==end)
    		goto error;
    
    	ucs mask = 16; //0001 0000
    	result = (result << 6) | (*iter++ & 0x3F); //... 0011 1111
    	if(result & (mask <<= 7))
    		return result;
    
    	if(iter==end)
    		goto error
    
    	result = (result << 6) | (*iter++ & 0x5F);
    	if(result & (mask <<= 7))
    		return result;
    
    	if(iter==end)
    		goto error
    	result = (result << 6) | (*iter++ & 0x5F);
    	if(result & (mask <<= 7))
    		return result;
    
    error:
    	throw std::runtime_error("wrong utf8 encoding");
    }
    

    zumindest compiliert es - könnte sein, dass es auch noch funktioniert ;o)

    übrigens: ich hatte im eingangspost auch gefragt, inwiefern man bei der namensgebung der labels aufpassen muss - ich hab noch keine antwort darauf gesehen(ich hoffe, ich hab sie nicht überlesen^^)

    bb



  • Hm... es gelten erst mal die üblichen Benennungsregeln für Bezeichner. Der ist auch nur in der Funktion sichtbar, nirgendwo sonst, das macht also keine Probleme.



  • Ad aCTa schrieb:

    Der ist auch nur in der Funktion sichtbar, nirgendwo sonst, das macht also keine Probleme.

    Gut - das wusste ich nämlich nicht... Danke



  • Dieses "goto error" kann aber die Fehlersucher erheblich erschweren.

    Begründung: Im Stacktrace erscheint die Stelle an der der throw ausgelöst wurde, in dem Beispielfall immer das Ende der Funktion. Man könnte nicht unterscheiden an welcher der vier Stellen denn der Fehler aufgetreten ist.

    Statt dessen würde ich das z.B. mit einer kleinen Hilfsfunktion lösen:

    inline void Check(bool bedingung, char message)
    {
        if( !bedingung ) throw std::runtime_error(message);
    }
    
    template <typename InputIterator>
    static ucs4 get_ucs4_from_utf8(InputIterator &iter, InputIterator end)
    {
        ucs4 result = ucs4(*iter++);
        if(result < 128)
            return result; //standard ascii character
        Check( result & 64, "wrong utf8 encoding");
    
        Check( iter!=end, "wrong utf8 encoding");
    
        ucs mask = 16; //0001 0000
        result = (result << 6) | (*iter++ & 0x3F); //... 0011 1111
        if(result & (mask <<= 7))
            return result;
    
        Check( iter!=end, "wrong utf8 encoding");
    
        result = (result << 6) | (*iter++ & 0x5F);
        if(result & (mask <<= 7))
            return result;
    
        Check( iter!=end, "wrong utf8 encoding");
    
        result = (result << 6) | (*iter++ & 0x5F);
        Check(result & (mask <<= 7), "wrong utf8 encoding");
    
        return result;
    }
    

    Jetzt erscheint im Stacktrace immer die Stelle an der der Fehler auch aufgetreten ist. UNd ganz ohne goto...



  • mist, da wollte ich einmal goto haben und schon wird es mir ausgeredet.



  • ok - da hatet ich zwar auch drüber nachgedacht, dachte mir dann aber, dass es mal völlig egal ist, wo genau der fehler auftritt - das einzig wichtige war für mich halt, dass es eine nicht standard-utf8 codierung war...

    bb


Anmelden zum Antworten