abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 18:00 | IT novinky

    DuckDuckGo AI Chat umožňuje "pokecat si" s GPT-3.5 Turbo od OpenAI nebo Claude 1.2 Instant od Anthropic. Bez vytváření účtu. Všechny chaty jsou soukromé. DuckDuckGo je neukládá ani nepoužívá k trénování modelů umělé inteligence.

    Ladislav Hagara | Komentářů: 0
    dnes 14:22 | IT novinky

    VASA-1, výzkumný projekt Microsoftu. Na vstupu stačí jediná fotka a zvukový záznam. Na výstupu je dokonalá mluvící nebo zpívající hlava. Prý si technologii nechá jenom pro sebe. Žádné demo, API nebo placená služba. Zatím.

    Ladislav Hagara | Komentářů: 2
    dnes 04:44 | Nová verze

    Nová čísla časopisů od nakladatelství Raspberry Pi: MagPi 140 (pdf) a HackSpace 77 (pdf).

    Ladislav Hagara | Komentářů: 0
    dnes 01:00 | Nová verze

    ESPHome, tj. open source systém umožňující nastavovat zařízení s čipy ESP (i dalšími) pomocí konfiguračních souborů a připojit je do domácí automatizace, například do Home Assistantu, byl vydán ve verzi 2024.4.0.

    Ladislav Hagara | Komentářů: 0
    včera 22:11 | IT novinky Ladislav Hagara | Komentářů: 0
    včera 20:55 | Nová verze

    Neziskové průmyslové konsorcium Khronos Group vydalo verzi 1.1 specifikace OpenXR (Wikipedie), tj. standardu specifikujícího přístup k platformám a zařízením pro XR, tj. platformám a zařízením pro AR (rozšířenou realitu) a VR (virtuální realitu). Do základu se z rozšíření dostalo XR_EXT_local_floor. Společnost Collabora implementuje novou verzi specifikace do platformy Monado, tj. open source implementace OpenXR.

    Ladislav Hagara | Komentářů: 2
    včera 17:22 | Nová verze

    Byla vydána nová verze 0.38.0 multimediálního přehrávače mpv (Wikipedie) vycházejícího z přehrávačů MPlayer a mplayer2. Přehled novinek, změn a oprav na GitHubu. Požadován je FFmpeg 4.4 nebo novější a také libplacebo 6.338.2 nebo novější.

    Ladislav Hagara | Komentářů: 13
    včera 17:11 | Nová verze

    ClamAV (Wikipedie), tj. multiplatformní antivirový engine s otevřeným zdrojovým kódem pro detekci trojských koní, virů, malwaru a dalších škodlivých hrozeb, byl vydán ve verzích 1.3.1, 1.2.3 a 1.0.6. Ve verzi 1.3.1 je mimo jiné řešena bezpečnostní chyba CVE-2024-20380.

    Ladislav Hagara | Komentářů: 2
    včera 12:11 | IT novinky

    Digitální a informační agentura (DIA) oznámila (PDF, X a Facebook), že mobilní aplikace Portál občana je ode dneška oficiálně venku.

    Ladislav Hagara | Komentářů: 10
    včera 05:11 | Komunita

    #HACKUJBRNO 2024, byly zveřejněny výsledky a výstupy hackathonu města Brna nad otevřenými městskými daty, který se konal 13. a 14. dubna 2024.

    Ladislav Hagara | Komentářů: 2
    KDE Plasma 6
     (68%)
     (10%)
     (2%)
     (20%)
    Celkem 564 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    Programátorská hádanka

    11.3.2007 13:52 | Přečteno: 2501× | Java | poslední úprava: 11.3.2007 20:37

    Jak si mnozí všimli, Abíčko v poslední době občas k nějakému písmenku s diakritikou přidalo jako bonus to samé písmenko ještě jednou zdarma. Chyba byla v zpracování UTF-8 znaků v serveru Jetty. Při hledání chyby i snaze chybu opravit se ukázalo, že příslušný kód je docela dobrá programátorská hádanka. Pokud chcete po nedělním obědě potrápit mozkové závity něčím jiným, než Sudoku, můžete se pustit do přiloženého kódu. Je sice napsaný v Javě, ale chyba je v algoritmu – nejde tedy o žádný chyták typu „jaké zobrazení reálných čísel používá jazyk XY“; odpůrci Javy si klidně mohou představit, že jde o kód v trochu divném C++.

    Co následující kód (mírně zjednodušená verze skutečného kódu z Jetty) dělá je jasné na první pohled (od toho tam ten komentář je, že). Jak to dělá už tak jasné není. Ta nejdůležitější otázka pak samozřejmě zní: jak kód co nejefektivněji opravit? V aktuální verzi Jetty už je chyba opravená, takže nepodvádějte – třeba najdete ještě lepší řešení, než je to současné. Za odměnu řešiteli pak takové řešení navrhnu na zařazení do Jetty :-)

    Aktualizováno: v diskuzi už je správné řešení. Pořád ještě ale můžete najít nějaké lepší řešení. Nebo dokázat, že lepší řešení neexistuje :-)

    public void write (String s,int offset, int length) throws IOException
    {      
        while (length > MAX_OUTPUT_CHARS)
        {
    	write(s, offset, MAX_OUTPUT_CHARS);
    	offset += MAX_OUTPUT_CHARS;
    	length -= MAX_OUTPUT_CHARS;
        }
    
        if (_out._chars==null)
    	_out._chars = new char[MAX_OUTPUT_CHARS]; 
        char[] chars = _out._chars;
        s.getChars(offset, offset + length, chars, 0);
        write(chars, 0, length);
    }
    
    public void write (char[] s,int offset, int length) throws IOException
    {      
        Output out = _out; 
        while (length > 0)
        {  
    	
    	int chunk = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
    	// WRITE_UTF8
    	byte[] buffer=out._bytes.getBuf();
    	int bytes=out._bytes.getCount();
    
    	if (chunk>buffer.length-bytes)
    	    chunk=buffer.length-bytes;
    	
    	for (int i = 0; i < chunk; i++)
    	{
    	    int code = s[offset+i];
    
    	    if ((code & 0xffffff80) == 0) 
    	    {
    		// 1b
    		buffer[bytes++]=(byte)(code);
    	    }
    	    else if((code&0xfffff800)==0)
    	    {
    		// 2b
    		if (buffer.length-bytes<2)
    		{
    		    chunk=i;
    		    break;
    		}
    		buffer[bytes++]=(byte)(0xc0|(code>>6));
    		buffer[bytes++]=(byte)(0x80|(code&0x3f));
    		
    		if (chunk-i>buffer.length-bytes)
    		    chunk=buffer.length-bytes+i;
    	    }
    	    else if((code&0xffff0000)==0)
    	    {
    		// 3b
    		if (buffer.length-bytes<3)
    		{
    		    chunk=i;
    		    break;
    		}
    		buffer[bytes++]=(byte)(0xe0|(code>>12));
    		buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
    		buffer[bytes++]=(byte)(0x80|(code&0x3f));
    
    		if (chunk-i>buffer.length-bytes)
    		    chunk=buffer.length-bytes+i;
    	    }
    	    else if((code&0xff200000)==0)
    	    {
    		// 4b
    		if (buffer.length-bytes<4)
    		{
    		    chunk=i;
    		    break;
    		}
    		buffer[bytes++]=(byte)(0xf0|(code>>18));
    		buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
    		buffer[bytes++]=(byte)(0x80|(code&0x3f));
    		
    		if (chunk-i>buffer.length-bytes)
    		    chunk=buffer.length-bytes+i;
    	    }
    	    else if((code&0xf4000000)==0)
    	    {
    		// 5
    		if (buffer.length-bytes<5)
    		{
    		    chunk=i;
    		    break;
    		}
    		buffer[bytes++]=(byte)(0xf8|(code>>24));
    		buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
    		buffer[bytes++]=(byte)(0x80|(code&0x3f));
    		
    		if (chunk-i>buffer.length-bytes)
    		    chunk=buffer.length-bytes+i;
    	    }
    	    else if((code&0x80000000)==0)
    	    {
    		// 6b
    		if (buffer.length-bytes<6)
    		{
    		    chunk=i;
    		    break;
    		}
    		buffer[bytes++]=(byte)(0xfc|(code>>30));
    		buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
    		buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
    		buffer[bytes++]=(byte)(0x80|(code&0x3f));
    		
    		if (chunk-i>buffer.length-bytes)
    		    chunk=buffer.length-bytes+i;
    	    }
    	    else
    	    {
    		buffer[bytes++]=(byte)('?');
    	    }
    	}
    	out._bytes.setCount(bytes);
    	out._bytes.writeTo(out);
    	out._bytes.reset();
    	length-=chunk;
    	offset+=chunk;
        }
    }
    
           

    Hodnocení: 100 %

            špatnédobré        

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    11.3.2007 15:30 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Hmm, trochu OT, ale dosti mě překvapuje že takový nenažraný moloch s neskutečně komplexními API na kdejakou kravinu neobsahuje triviální věc jako konverzi z UCS-2 do UTF-8 v nějaké nativní knihovně, takže to programátor musí bastlit na aplikační úrovni. Se pak nedivte že je to pomalý- vrtět se v Javě pro každej char co se vyplivne...
    Táto, ty de byl? V práci, já debil.
    11.3.2007 16:00 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Java takové prostředky samozřejmě obsahuje. Jenže tady je potřeba, aby to bylo rychlé, aby se to nezaseklo na neznámých znacích, aby bylo možné řídit bufferování atd. V případě, kde je kritická rychlost, se holt musí zapomenout na univerzální řešení a implementovat to znova, na míru dané situaci. To platí nejen pro Javu, ale pro všechny programovací jazyky.
    13.3.2007 13:07 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Aha, takže ty existující prostředky jsou pomalé, nebo se zasekávají na neznámých znacích? Nebylo by lepší je opravit? Tím "řízením bufferování" myslíte co? Mám knihovní funkci, pošlu jí Java string, ona alokuje a vrátí UTF-8 buffer, který pak pošlu do socketu. Jistě, jeho velikost nevím předem, ale znám dolní i horní limit, a když toho bude moc (je vůbec nějaký důvod pro sekání výstupu na pevné chunky?) jednoduše kus výsledku uříznu, schovám a pošlu příště, ne? Nevidím žádný důvod proč tyhle věci dělat *během* konverze..
    Táto, ty de byl? V práci, já debil.
    13.3.2007 13:29 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Aha, takže ty existující prostředky jsou pomalé, nebo se zasekávají na neznámých znacích? Nebylo by lepší je opravit?
    Kdo říkal zasekávají? Jenom možná pro účely webového serveru není vyhození výjimky úplně ten nejlepší způsob, jak se s takovým znakem popasovat. Na druhou stranu, tohle je spíš jen teorie, protože se těžko někomu podaří v Javě zadat znak, který nejde zakódovat v UTF-8.
    Tím "řízením bufferování" myslíte co? Mám knihovní funkci, pošlu jí Java string, ona alokuje a vrátí UTF-8 buffer, který pak pošlu do socketu.
    A to je právě to, co nechci. Mám funkci, která odněkud načítá String, až ho bude mít 2 MB, tak ho pošlu knihovní funkci, ta naalokuje buffer 2,5 MB, do něj String převede a pak už konečně můžu začít něco odesílat do socketu. A uživatel u prohlížeče zatím může jít na kafe. To by pak všechny ty prostředky HTTP a serveru, které umožňují průběžné odesílání, byly k ničemu, ne?
    13.3.2007 13:44 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    To by pak všechny ty prostředky HTTP a serveru, které umožňují průběžné odesílání, byly k ničemu, ne?
    To přece spolu vůbec nesouvisí, můžu načíst/vygenerovat pár stovek bajtů, ty překódovat, odeslat (jako http chunked), a číst dál.. Pokud opravdu máte funkci která něco načítá a vrátí se teprve až bude mít 2MB, k žádnému "průběžnému" překódování a odesílání se stejně nedostanete. Vše co jsem tvrdil je že je blbost dělat cokoliv dodatečného (jako třeba kontrola výstupního bufferu) během zpracování každého znaku- není pro to důvod, a je to neefektivní.
    Táto, ty de byl? V práci, já debil.
    13.3.2007 13:55 happy barney | skóre: 34 | blog: dont_worry_be_happy
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    :-) ideálny prípad: načítava z UTF-8, konvertuje do interného, a potom do UTF-8, ak tomu rozumiem správne :-)
    13.3.2007 14:13 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Jo, Java se tím zřejmě zbavuje přebytečných cpu cyklů.. a aby nebyla nuda tak současně mrší unicode znaky mimo BMP. :-)
    Táto, ty de byl? V práci, já debil.
    13.3.2007 15:47 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    To přece spolu vůbec nesouvisí, můžu načíst/vygenerovat pár stovek bajtů, ty překódovat, odeslat (jako http chunked), a číst dál..
    Takže nechám onu knihovní funkci pro každých pár stovek bajtů vytvořit buffer, překódovat, zahodit buffer. A pak se lidi jako vy začnou divit, že je to pomalé a že za to určitě může ta Java.
    Vše co jsem tvrdil je že je blbost dělat cokoliv dodatečného (jako třeba kontrola výstupního bufferu) během zpracování každého znaku- není pro to důvod, a je to neefektivní.
    Vzhledem k tomu, že se v tom kódu žádná kontrola výstupního bufferu nedělá, nevím, o čem zde píšete.
    13.3.2007 15:54 happy barney | skóre: 34 | blog: dont_worry_be_happy
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    samozrejme, že za to môže java :-)
    V C by to jeden elegantne vyriešil pointrom :-D

    13.3.2007 16:25 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Schválně někdy zkusím porovnat, jaký bude rozdíl v rychlosti převádění jako Stringu, současné implementace, a využití OutputStreamWriter (což by bylo asi nejblíž Cčkové implementaci s pointerem). Pokud by ten OutputStreamWriter nebyl výrazně pomalejší, stálo by za to kód přepsat (resp. vyhodit tu podmínku, která UTF-8 zpracovává jinak, jiná kódování než UTF-8 a ASCII už tímhle způsobem zpracovávána jsou). Dříve to tak ale bylo, ta změna na současný způsob asi má nějaký důvod…
    13.3.2007 17:16 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Strčení bajtu do bufferu s postinkrementem indexu bude ZCELA URČITĚ rychlejší než jen samotný call overhead toho OutputStreamWriteru (Javovská obsese dlouhými názvy je fakt k popukání- jako by mohl existovat nějaký InputStreamWriter, hahaha). Navíc tím že uvnitř smyčky nebudou žádná volání jiných funkcí je celá smyčka leaf code block, takže JIT může proměnné vrazit do scratch registrů cpu, a vygeneruje proto celkově o dost lepší kód... Podle mě tohle byla jasná motivace proč to přepsat jako kopírování z jednoho bufferu do druhého.
    Táto, ty de byl? V práci, já debil.
    13.3.2007 17:22 happy barney | skóre: 34 | blog: dont_worry_be_happy
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    :-) čím dlhšie mená, tým viac znakov => väčšie súbory => väčšia výkonnosť programátorov. Navyše aj menšia chybovosť, pretože je vysoká pravdepodobnosť, že programátora trkne, keď bude písat OutputStreamWriter.read
    13.3.2007 18:53 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    JIT může stejně dobře celé volání funkce inlineovat, takže pak provádění bude stejně rychlé, ale nebude nutné znovu (s chybami) implementovat něco, co už bylo jednou implementováno. Mimochodem, trochu jsme si prohodili role :-)

    Ten název je celkem logický, protože je to OutputStream, který implementuje Writer. Používání dlouhých názvů, ze kterých je patrné, o co jde, patří k dobrým praktikám programování v Javě.
    14.3.2007 09:50 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Inlinování bez profilovacích informací je magie, podle mě by se překladač ani JIT neměl vůbec pokoušet hádat co inlinovat a co ne. Pokud programátor něco explicitně inlinuje (jde to vůbec v Javě?), tak proč ne, ale u moderních cpu jsou kódová cache a instrukční dekodéry často limitující a příliš agresivní inlinování je může snadno přeplnit a snížit tak hit rate. Dlouhé názvy: To je sice pravda ale pokud OutputStream implementuje Writer, tak jej člověk netrpící grafomanií nazve StreamWriter, neboť to že jde o výstupní stream je zjevné už z toho Writer. K prohození rolí: Co tím myslíte? Když určité chování jednoho Javovského programátora považuji za rozumné tak to přece neznamená že obhajuju Javu :)
    Táto, ty de byl? V práci, já debil.
    14.3.2007 10:33 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Překladač rozhodně neinlinuje, od JIT se to naopak dá plným právem očekávat, kdo jiný už by měl mít potřebné informace, než JIT? Explicitně inlinovat v Javě nejde, Java je postavená na tom, že je multiplatformní a programátor by měl být co nejvíce odstíněn od implementačních detailů konkrétní HW platformy. Takže optimalizace tohoto typu nedělá programátor, optimalizace nedělá ani kompilátor, ale dělá je až JVM, které ví, na jaké platformě běží a může využít i informace z profilování kódu (takže zbytečně nekompiluje něco, co se v programu stejně nikdy neprovede, ale když už provádí nějaký kód potisící, může si říct, že by stálo za to ho zoptimalizovat a přeložit do strojového kódu).

    Jak by se z názvu StreamWriter poznalo, zda ten Writer zapisuje do OutputStream, FilteredOutputStream, BufferedOutputStream, FileOutputStream nebo do spousty dalších OutputStreamů?
    13.3.2007 16:36 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Takže nechám onu knihovní funkci pro každých pár stovek bajtů vytvořit buffer, překódovat, zahodit buffer. A pak se lidi jako vy začnou divit, že je to pomalé a že za to určitě může ta Java.
    Nevěřím že alokace prázdného bufferu plus jeho GC má režii srovnatelnou nebo větší než pár stovek iterací oné for (int i..) smyčky. I kdyby ano, samozřejmě by každý thread mohl recyklovat jeden dostatečně velký buffer.
    Vzhledem k tomu, že se v tom kódu žádná kontrola výstupního bufferu nedělá, nevím, o čem zde píšete.
    Ale dělá.. sice jen ve větvi //2b, ale zato dvakrát :-) Nejdřív se kouká jestli jsou volné aspoň 2 bajty, pak ještě jestli je dost místa pro zbytek chunku za (pro češtinu) nesmyslně optimistického předpokladu že ani jeden zbývající znak nebude multibyte.
    Táto, ty de byl? V práci, já debil.
    13.3.2007 19:10 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Nevěřím že alokace prázdného bufferu plus jeho GC má režii srovnatelnou nebo větší než pár stovek iterací oné for (int i..) smyčky. I kdyby ano, samozřejmě by každý thread mohl recyklovat jeden dostatečně velký buffer.
    Těch iterací se ale nelze zbavit. Daly by se oželet některé podmínky, za cenu výrazného zvýšení spotřeba paměti. vytváření a rušení objektů sice bylo hodně optimalizováno, ale zase je neustále alokovat a rušit pro každých pár znaků…

    Recyklovat buffer pro thread už by šlo, jenže takováhle speciální funkce je potřeba tak málo, že se nevyplatí dávat jí do standardní knihovny. Její použití znamená, že je potřeba nějakou část hodně zoptimalizovat, a v takovém případě už každý radši napíše svou implementaci. Než zjistit, že by tu speciální knihovní metodu mohl použít, ale nevyhovuje mu způsob synchronizace onoho bufferu, nebo jeho velikost, nebo nemůže určit optimální odhad o kolik jej nafouknout oproti počtu znaků…
    Ale dělá.. sice jen ve větvi //2b, ale zato dvakrát :-) Nejdřív se kouká jestli jsou volné aspoň 2 bajty, pak ještě jestli je dost místa pro zbytek chunku za (pro češtinu) nesmyslně optimistického předpokladu že ani jeden zbývající znak nebude multibyte.
    Pro českou webovou stránku vychází nárůst UTF-8 oproti Latin-2 zhruba 1,03 násobek. Kvůli tomu vytvářet 6násobně velký buffer?
    11.3.2007 15:33 peterh
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Myslim, ze to uz Leos niekde prezradil (v com bola chyba).
    11.3.2007 16:04 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Leoš i já jsme to několikrát napsali, ale to byla vždycky informace o tom, co se dělo špatně. V tomhle případě ale není úplně na první pohled jasné, kde (v kódu) a proč se tak dělo. Alespoň já při debugování jsem poměrně brzy zjistil, že problém je v téhle metodě, ale zjistit, kde přesně je problém a jak ho opravit, to už trvalo dýl.
    11.3.2007 16:45 the two
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    ten nepodminenej break uprostred cyklu vypada vazne zajimave... Ale ten by asi pismena nezdvojoval. Spis by se dalo predpokladat, ze semtam nejaky zmizi
    11.3.2007 17:09 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Omlouvám se, ten break tam nemá co dělat, je to pozůstatek zjednodušování. Už jsme ho vymazal. S tím breakem by ten program hlavně zůstal v nekonečné smyčce.
    11.3.2007 19:56 the two
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    typoval bych tohle:
    if (chunk-i>buffer.length-bytes)
    	chunk=buffer.length-bytes+i+1;
    
    pripadne by tam slo doplnit jeste jednu jednicku, ale neni nutna:
    if (chunk-i-1>buffer.length-bytes)
    	chunk=buffer.length-bytes+i+1;
    
    11.3.2007 20:34 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    To chybné místo jste našel správně. S přidanou jedničkou by se to ale pokoušelo zapsat za konec bufferu. Ta mínus jednička v podmínce ve vašem druhém případě je to, co ten problém s opakováním znaku vyřeší, takže nutná je :-) Respektive je to nejjednodušší způsob, jak v té podmínce detekovat, že k zapsání máme víc znaků, než je volných bytů v bufferu, a zároveň ještě nějaké volné byty v bufferu máme.

    V proměnné chunk je počet znaků, které se se ještě vejdou do bufferu, pokud by všechny znaky byly jednobajtové. Na konci cyklu je to zároveň počet skutečně zapsaných znaků. Ta vámi uvedená podmínka testuje, zda se do bufferu ještě vejde chunk znaků, pokud budou všechny jednobajtové, pokud ne, tak se chunk zmenší. Pokud je to ale na konci bufferu, je to špatně – proměnná obsahuje hodnotu, kolik znaků by se dalo zapsat v příštím cyklu, ale příští cyklus se už neprovede, takže znak se sice do bufferu zapsal, ale v chunk je hodnota, jakoby se už nevešel. Takže je nutné otestovat, zda už nejsme na konci bufferu a v tom případě už chunk nesnižovat.

    Aktuální kód vypadá takhle:
    if (bytes+chunk-i-1>buffer.length)
      chunk-=1;
    
    (Respektive chunk-=2 pro 3bajtové znaky atd.)
    11.3.2007 22:51 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Kecám, ta -1 ve vašem případě v podmínce být nemusí, správně jsou oba případy. Nechal jsem se nachytat na to, že ta podmínka se přece nemůže lišit o jedničku od správného řešení. Může, protože v případě, že 1. podmínka splěná je ale 2. splněná není je přiřazovací příkaz vlastně chunk = chunk. Co je náročnější na CPU, zda odečtení jedničky, nebo přiřazení hodnoty, to už radši řešit nebudu :-)
    12.3.2007 01:07 Sinuhet | skóre: 31
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    V proměnné chunk je počet znaků, které se se ještě vejdou do bufferu, pokud by všechny znaky byly jednobajtové.
    No to prave ze ne. Asi nejvetsi pruser je totiz v tom, ze chunk v ruznych situacich obsahuje hodnoty vyjadrujici (a nekdy ani to ne) neco jineho. Tento kod
    	if (chunk-i>buffer.length-bytes)
    	    chunk=buffer.length-bytes+i;
    ve spojeni s podminkou ve for cyklu napr. ve vysledku vede k tomu, ze v pripade, kdy nam doslo misto v bufferu (buffer.length-bytes == 0) se cyklus prerusi a do chunk se ulozi pocet prednych znaku (ale blbe). Takze minimalne vsechny tyhle ify vyhodit a na konec foru dat
    	if( bytes >= buffer.length ) {
    		chunk = i+1;
    		break;
    	}
    Dale odstranit if (chunk>buffer.length-bytes) a rozseknout chunk na dve promenne 'pocet zapsanych znaku' a 'maximalni pocet znaku k zapsani'. Aby to bylo alespon trochu k pochopeni.
    12.3.2007 08:27 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Sice by to bylo jednodu
    šší na pochopení, ale pro nejčastější případ – znak z ASCII – by se v každém cyklu zbytečně testovala podmínka navíc. A v každém cyklu by se zbytečně aktualizovaly dvě proměnné místo jedné. Ale tohle je zrovna kód, kde je důležitá rychlost, čitelnost je až na druhém místě.
    

    Invariant, že chunk znamená "maximální počet znaků, který po skončení cyklu bude zapsán v bufferu" (na konci cyklu to tedy je "počet znaků zapsaných v bufferu"), a že zároveň tedy chunk-i je "maximální počet znaků, které se ještě do bufferu vejdou" platí v celém kódu. Problém je v tom, že i++ se provádí až na konci cyklu, ne hned v místě, kde se znak skutečně zapíše. A mezi místem, kde by se i mělo aktualizovat a kde se i ve skutečnosti aktualizuje, je ona problematická podmínka, kde se vyskytuje neaktualizované i. Složitě počítat chunk, pokud je potřeba jej zkrátit, je zbytečné, např. dvoubajtový znak si vzal z bufferu o jeden znak navíc "proti plánu", takže stačí udělat chunk-=1.

    Asi nejčitelnější a zároveň optimalizovaný kód by tedy byl:
    int i = 0;
    while (i < chunk) {
        int code = s[offset+i];
    
        if ((code & 0xffffff80) == 0) 
        {
    	// 1b
    	buffer[bytes++]=(byte)(code);
    	i++;
        }
        else if((code&0xfffff800)==0)
        {
    	// 2b
    	if (buffer.length-bytes<2)
    	{
    	    chunk=i;
    	    break;
    	}
    	buffer[bytes++]=(byte)(0xc0|(code>>6));
    	buffer[bytes++]=(byte)(0x80|(code&0x3f));
    	i++;
    
    	if (chunk-i>buffer.length-bytes)
    	    chunk-=1;
        }
    …
    
    13.3.2007 16:45 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Jo, to je mírně lepší. Ale podle mě by bylo nejlepší z vnitřní smyčky vyhodit VŠECHNY testy výstupního bufferu. Dostanu chunk 150 neznámých znaků a výstupní UTF-8 buffer pro 200 bajtů? V nejhorším budu kopírovat 1:2, takže 200 bajtů vystačí na 100 znaků- proto zpracuju 100 znaků bez jakékoliv kontroly a zbylých 50 udělám v další iteraci. Jednoduché a efektivní.
    Táto, ty de byl? V práci, já debil.
    13.3.2007 19:02 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Tenhle výpočet nějak nechápu. V nejhorším případě se mi do bufferu na 200 bajtů vejde 33 znaků (UTF-8 může kódovat 1 znak až jako 6 bajtů). Zpracuji tedy 33 znaků bez jakékoli kontroly, předám buffer k odeslání do socketu a mezi tím si vytvořím další buffer do kterého budu pokračovat se zápisem. Pro nejrozšířenější případ – jednobajtové znaky – tedy neustále vytvářím a zahazuju 6násobně větší buffery.
    13.3.2007 20:32 happy barney | skóre: 34 | blog: dont_worry_be_happy
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    200 / 6 = 33 bez kontroly, dĺžka povedzme 48, ostalo 152
    152 / 6 = 25 bez kontroly, ... atd ...

    plus mať overflow buffer, aby sa nemuselo "vracať"

    14.3.2007 11:09 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Zajímavej nápad, takhle to postupně skládat do stejného bufferu mě nenapadlo.. ale v nejhorším případě to může vést ke geometricky klesající posloupnosti, a poměrně hodně iteracím té vnější smyčky.. asi fakt nejlepší řešení je něco jako:
    Byte[] UCS4_to_utf8(int[] in) {
      int in_l = in.length, out_l = 0;
      Byte[] out = malloc(6 * in_l);
    
      for (int i = 0; i < in_l;) {
        int c = in[i++];
    
        if (c & bflm == 0) // 1b
          out[out_l++] = c;
        else if (c & psvz == 0) // 2b
          out[out_l++] = c1,
          out[out_l++] = c2;
        ..
        else if (c & xyzy == 0) // 6b
          out[out_l++] = c1,
          out[out_l++] = c2,
          out[out_l++] = c3,
          out[out_l++] = c4,
          out[out_l++] = c5,
          out[out_l++] = c6;
      }
      return out.realloc(out_l);
    }
    

    Dokonce bych se ani nedivil kdyby systém nějak speciálně optimalizoval realloc(), který upravuje velikost bloku, který daný thread těsně předtím alokoval- myslím že postup malloc(hodně), process(), realloc(málo) je docela běžný..
    Táto, ty de byl? V práci, já debil.
    14.3.2007 11:42 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Zajímavej nápad, takhle to postupně skládat do stejného bufferu mě nenapadlo.. ale v nejhorším případě to může vést ke geometricky klesající posloupnosti, a poměrně hodně iteracím té vnější smyčky..
    Bál bych se toho samého, navíc pro čistě ASCII texty tam bude ta vnější smyčka pouze navíc, a i pro češtinu bych si tipnul, že overhead vnější smyčky bude větší, než to, co se ušetří u znaků //>>2b
    Dokonce bych se ani nedivil kdyby systém nějak speciálně optimalizoval realloc(), který upravuje velikost bloku, který daný thread těsně předtím alokoval- myslím že postup malloc(hodně), process(), realloc(málo) je docela běžný..
    malloc a realloc ale v Javě nenapíšete :-) A volat kvůli tomu nativní funkce… JVM používá vlastní správu paměti (vezme si od systému větší kus a ten pak přiděluje ve vlastní režii), takže chování systémových nebo knihovních funkcí pro alokaci paměti nemá přímý vliv na alokaci paměti v Javě.
    14.3.2007 13:43 happy barney | skóre: 34 | blog: dont_worry_be_happy
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    keď sa niečoho bojíte, tak:
    - output buffer = 2048 ? ... working buffer = 6 * 2048
    - ak vo working je menej ako 2048, dopisat 2048 - koĺko je
    - do output zapísať 2048

    14.3.2007 10:11 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Nezklamal, nezklamal.. Já věděl že budete mermomocí tu dvojku chtít změnit na šestku, přestože jsme se už shodli na tom že ty větve // 3-6b jsou unreachable. :) Ale to je jedno, třeba Baňáka, třeba 6x.. V čem je hlavní pointa je že počítač ani tak nezajímá kolik paměti alokujete, jako spíš kolik jí použijete. Takže když pro zpracování 2k znaků alokuju třeba 1MB buffer, ale zapíšu do něj jen 3kB, VM si vystačí s jednou stránkou fyzické paměti, a nepotřebuje někde vybagrovat všech 256.
    Táto, ty de byl? V práci, já debil.
    14.3.2007 10:23 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    To, že jsou větve //3-6b unreachable je chyba, optimalizovat program na chybu snad nebudeme… Pokud VM potřebuje alokovat 1MB buffer, bude se třeba pokoušet najít 1MB souvislý blok v již alokované paměti, který pak celý pro využití v bufferu zamkne. Pokud pak bude paměť potřebovat jiná část programu, bude už muset třeba alokovat novou paměť od OS. Fyzické paměti se to sice nedotkne, ale zpomalení programu to je.
    14.3.2007 10:46 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Moderní alokátory (tj cokoliv lepšího než first fit apod) mají režii prakticky konstantní, nezáleží na velikosti požadovaného bloku. Dokonce, tyhle "větší" bloky se naopak hledají spíše rychleji.. Když alokátor tolik nepálí fregmentace (ví že ji za něj řeší VM), může používat rychlejší algoritmy (třeba buddy system).
    Táto, ty de byl? V práci, já debil.
    11.3.2007 20:39 Atom321 | skóre: 20
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Pokud si chcete tuto úlohu vyřešit sami, tohle nečtěte.

    1) Už použitím otazníkového operátoru autor kódu prozradil, že rád píše program tak, aby vypadal sofistikovaně. Že se tím snižuje čitelnost kódu, to je vedlejší. Nicméně, toto není ten problém.

    Upozornění: Těmito řádky tvrzením nechci autora nijak urážet ani hanět, nebo se na někoho vytahovat. Stejné chyby jsem dělal taky. Lidově řečeno, nakopaly mi prdel a snad jsem se z toho poučil.

    2) Konstrukce:
    if (chunk-i>buffer.length-bytes)
        chunk=buffer.length-bytes+i;
    
    Se mi zdála podezřelá už od počátku, protože:

    a) Mění proměnnou "chunk" použitou v řízení cyklu for. To je sám o sobě trik který také snižuje čitelnost (některé jazyky to ani neumožňují). Z nečitelnosti vznikají těžko hledatelné chyby. Ale ani toto není ten problém.

    b) Míchá proměnné s různými významy. Proměnná "i" je index na aktuálně zpracovávaný znak, zatímco "bytes" je index prvního volného bytu ve výstupním bufferu. A to je ten problém :-)

    (Bude následovat úplné prozrazení. Pokud chcete ještě dumat, dále nečtěte.)

    Proměnná "chunk" má zjevně význam "počet zpracovaných znaků v této obrátce". Řádky:
      length-=chunk;
      offset+=chunk;
    
    Posouvají ukazatel "offset" o počet zpracovaných znaků. Fígl je v tom, že konstrukce:
      chunk=buffer.length-bytes+i;
    
    má do "chunk" uložit počet zpracovaných znaků na vstupu + zbývající místo na výstupu. To ale nedělá. Výpočet "buffer.length-bytes" udává správně volné místo, ale v "i" není počet zpracovaných znaků, nýbrž (jak jsem napsal výše) index na aktuálně zpracovávaný znak, který je však o 1 nižší. (Znaky jsou indexované od nuly - tj. pokud např. zpracovávám pátý znak, má index 4.) Do "chunk" se tak vloží hodnota o jednu menší (tedy bez aktuálního znaku). Pokud není v bufferu už žádné místo, cyklus se ukončí, tento poslední znak se vypíše, ale nezapočítá do posunu length a offset. V následující obrátce nadřízeného cyklu "while (length > 0)" se zpracuje ještě jednou.

    Jednoduchá oprava:

    místo:
    -----
    	for (int i = 0; i < chunk; i++)
    	{
    	    int code = s[offset+i];
    -----
    
    bych napsal:
    -----	
    	int i=0;
    	while (i < chunk)
    	{
    	    int code = s[offset+i];
    	    i++;
    -----
    
    Po této úpravě je "i" o jednu vyšší než předtím. Má tak význam "index na první nezpracovaný znak", tj. totéž co "počet načtených znaků". Krom toho místo cyklu for je použit while, u kterého se dají více předpokládat záludnosti v řídících proměnných :-)

    Osobně si ale myslím, že by to zasloužilo přepsat celé.
    11.3.2007 21:15 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    Taky je to možné řešení, bylo by pak nutné ještě ve vnitřku podmínek „znak už se celý nevejde“ tu jedničku zase odečíst:
    if (buffer.length-bytes<2)
      {
        chunk=i-1;
        break;
      }
    
    A to samé v nastavení délky chunku:
    if (chunk-i>buffer.length-bytes)
      chunk=buffer.length-bytes+i-1;
    
    Mně osobně ale váš kód přijde ještě složitější na pochopení, než originál. Úplně se v něm ztrácí to, že chunk není jen počet zapsaných znaků v této obrátce (tenhle význam má až po ukončení cyklu for), ale zároveň chunk-i znamená maximální počet znaků, které se do bufferu ještě vejdou, a zajišťuje to nepřetečení bufferu. A budu-li detailista, váš kód přičte jedničku zbytečně i v případě, kdy se už celý znak do bufferu nevejde a cyklus se ukončí breakem :-)
    11.3.2007 22:22 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Programátorská hádanka
    To moje druhé odečtení -1 už je samozřejmě špatně, tam už je hodnota i zvětšená správně. Ono by bylo vůbec nejlepší to i++ provést těsně před nebo těsně po buffer[bytes++], sice by to bylo v kódu zopakované několikrát, ale bylo by to na místě, kde skutečně k tomu zápisu znaku dojde.
    13.3.2007 11:00 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Další Java-divnosti..
    MMCH co znamená if((code&0xffff0000)==0) ?!?

    code je char, a Java jej odjakživa pevně definuje (což je ohromná výhoda proti zpátečnickému C) jako uint16_t, takže uvedený kód nemá smysl, neboť podmínka bude vždy neplatná.

    Táto, ty de byl? V práci, já debil.
    13.3.2007 11:25 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    No vida, to je chyba. Asi by se to mělo přepsat, aby se používalo Character.codePointAt(). Opravíte to v Jetty nebo se o to mám postarat?
    13.3.2007 12:51 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Java přechází z UCS-2 na UTF-16? Ojedinělý pokus o zkombinování paměťové neefektivity šestnáctibitového datového typu se zvýšenou složitostí a pomalostí kódu, plynoucí z kódování znaků do proměnné délky :) Funny as hell.. a jak to chcete opravovat? UTF-16 je v Javě rozbité tak nějak celkově, aspoň tak chápu podle toho co mi vyplivl Google..

    http://www.stylusstudio.com/xmldev/200003/post10200.html
    http://www.ingrid.org/java/i18n/utf-16/

    Jediné rozumné cesty jsou:
    a) oficiálně nepodporovat codepoints nad 0xffff (fakticky současný stav)
    b) změnit char na uint32_t (a potenciálně tak rozbít starý kód)
    c) (varinta na b) udělat String plně transparentní (volitelně UCS-4 nebo UTF-8 při spouštění JVM), tj věci jako length(), substr(), indexování, atd by se pak nad UTF-8 stringy chovaly jako by neobsahovaly multibyte znaky.

    Ale přecházet na UTF-16 je podle mě strašná blbost, i když uznávám že jde o cestu nejmenšího odporu, jenže přesně to je cesta která Javu přivedla od dobrého nápadu do té p****e kde je teď.

    Táto, ty de byl? V práci, já debil.
    13.3.2007 13:24 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Ještě je cesta d) – přečíst si JavaDoc a zjistit, že Java 5 už Unicode se znaky > 0xffff podporuje. Vizte java.lang.Character.
    13.3.2007 14:02 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    To je ale stále možnost b), jen ten "novej" 21-bitovej char přejmenovali na Character, takže Java programátoři mají možnost volby co kde použijí. Jinými slovy, byli požehnáni další dimenzí, do které mohou rozvíjet bugy ve svém kódu. :) Navíc, implementovat unicode znaky nikoliv jako literály ale jako instance nějaké třídy je fakt #@%&^@#^.. ále, co bych se rozčiloval...
    Táto, ty de byl? V práci, já debil.
    13.3.2007 15:42 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Stálo by za to si ten zmiňovaný a nalinkovaný JavaDoc přečíst. java.lang.Character je v Javě odjakživa (to znamená to "Since 1.0"). char je pořád 16bitový, ale přibyla možnost číst Unicode CodePoints jako int. Ono co s tím taky dělat jiného, když se Unicode neočekávaně rozrostlo nad 16 bitů. Znakový literál je stále char, řetězcový literál je stále String, String je stále soubor charů, String.length() je stále počet char v řetězci, řetězce jsou stále uložené v UTF-16. Pouze přibyly metody pro práci se surrogates, tak jak je to ve Standardu Unicode. To že si tvůrci Unicode na začátku mysleli, že s 16 bity vystačí, a pak zjistili, že ne, není chyba žádného programovacího jazyka.
    13.3.2007 17:01 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Uff, z toho jsem jelen.. Ta dokumentace je děsně nepřehledná, nemůžu najít žádné non-static data members oné třídy Character- buď tam nejsou, nebo je ta tabulka míchá dohromady s konstantami, takže jsem je přehlédl.. Pokud je celá třída JEN zabalením nějakých statických metod pro práci se surrogates, pak nechápu proč si ten konstruktor bere argument, a jak mohou fungovat ty asi 3 nestatické metody, co tam jsou... nerozumím.
    Táto, ty de byl? V práci, já debil.
    13.3.2007 18:42 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Podpora Unicode je popsaná hned na začátku příslušného JavaDocu. Veřejná dokumentace dokumentuje veřejné API, do kterého dle dobrých zvyků OOP členské proměnné nepatří. Jinak třída Character má privátní datovou proměnnou value typu char.
    14.3.2007 09:25 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Aha, máte pravdu, je to tam- akorát nevím jak jste přišel na to že onen field se jmenuje právě value. An object of type Character contains a single field whose type is char. JavaDoc že privátní věci nekomentuje? Ale vždyť uvedená věta zjevně přesně toto dělá: popisuje privátní field! Jaký je proboha smysl mít docela pokročilý nástroj pro (formálně silný- tj tabulka jmen, typů a signatur) popis veřejného API, v něm současně popisovat i privátní záležitosti, ale dělat to zpátečnicky úplně jiným (neformální anglické věty) způsobem?

    Stále nechápu proč ten base typ je char, proč to není int. Nemá přece vůbec žádný smysl kopírovat proměnnou typu char do objektu který bude jen boxovat ten samý typ! Zato kdyby byl base typ pro Character int, mohl by mít konstruktor stejnou signaturou jako má teď codePointAt, pojmul by všechny Unicode znaky, a API by bylo mnohem průhlednější a jednodušší. Jistě, duplikoval by se tím typ int, ale mít v kódu formálně odlišeny numerické hodnoty od unicode codepointů má aspoň nějaký důvod. Nevím, přiznávám že proti Javě jsem dlouhodobě zaujatej, ale je fakt moc těžký nebýt zaujatej když prakticky všechno na co kouknu se mi jeví jako udělané zoufale blbě :(
    Táto, ty de byl? V práci, já debil.
    14.3.2007 10:48 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Aha, máte pravdu, je to tam- akorát nevím jak jste přišel na to že onen field se jmenuje právě value.
    Dalo by se to zjistit pohledem do zdrojáků, já to zjistil pohledem do Outline View příslušné třídy v eclipse.
    JavaDoc že privátní věci nekomentuje? Ale vždyť uvedená věta zjevně přesně toto dělá: popisuje privátní field! Jaký je proboha smysl mít docela pokročilý nástroj pro (formálně silný- tj tabulka jmen, typů a signatur) popis veřejného API, v něm současně popisovat i privátní záležitosti, ale dělat to zpátečnicky úplně jiným (neformální anglické věty) způsobem?
    Ve zdrojovém kódu je dobré komentovat i privátní věci, při generování JavaDocu si pak můžete vybrat úroveň podrobností, defaultně se privátní prvky, metody a třídy do JavaDocu negenerují.
    Stále nechápu proč ten base typ je char, proč to není int. Nemá přece vůbec žádný smysl kopírovat proměnnou typu char do objektu který bude jen boxovat ten samý typ! Zato kdyby byl base typ pro Character int, mohl by mít konstruktor stejnou signaturou jako má teď codePointAt, pojmul by všechny Unicode znaky, a API by bylo mnohem průhlednější a jednodušší. Jistě, duplikoval by se tím typ int, ale mít v kódu formálně odlišeny numerické hodnoty od unicode codepointů má aspoň nějaký důvod. Nevím, přiznávám že proti Javě jsem dlouhodobě zaujatej, ale je fakt moc těžký nebýt zaujatej když prakticky všechno na co kouknu se mi jeví jako udělané zoufale blbě :(
    Java má pro každý primitivní typ odpovídající třídu, která ten typ obaluje. Původně byla Java zamýšlena jako jazyk pro nejrůznější přístroje s nepříliš velkým výpočetním výkonem, primitivní typy byly zavedeny jako ústupek tomu nízkému výkonu – aby nebylo nutné i pro tyto typy alokovat "celý" objekt a nakonec jej zase rušit. Obalující typy jsou způsob, jak tyto primitivní typy přenést do světa OOP. Dnes už je jasné, že zavádět primitivní datové typy nebyla šťastná volba, ale na řešení už je pozdě – jedině udělat zcela novou Javu.
    14.3.2007 14:01 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    To že Java umí boxovat základní typy je naprosto v pořádku a já s tím nemám problém- řeší to problém s jejich ukládáním do kontejnerů apod. To že primitivní typy nejsou objekty je naopak dobré, nevím proč to hodnotíte jako omyl..

    Akorát nechápu proč to píšete, jak boxování v Javě souvisí s Unicode, a proč ten class Character je nad téměř nepoužitelným typem char, místo nad Unicode-kompatibilním 32-bit integerem.
    Táto, ty de byl? V práci, já debil.
    14.3.2007 14:07 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Protože char je základní typ a Character je jeho objektový protějšek. Podobně má int svůj objektový protějšek Integer, byte Byte atd. Cahracter tedy není typ, který by primárně řešil problém s narostlým Unicode, ale je to typ pro boxing primitivního typu char.
    14.3.2007 16:09 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Proč jste tedy class Character uváděl jako řešení problému s rozbitým char-em, když jde jen o boxovaný char. To opravdu Javovský programátor musí pro ukládání Unicode řetězců používat neprůhledné obezličky typu int[] ?
    Táto, ty de byl? V práci, já debil.
    14.3.2007 16:30 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Protože char je znak v UTF-16, String je řetězec znaků UTF-16, programátor s nimi může normálně pracovat. Pokud programátor tyto znaky chce převést na UTF-32 znaky, poskytuje mu k tomu třída Character API. Přesně podle doporučení Unicode konsorcia.
    14.3.2007 17:21 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Jestli máte na mysli stejnou třídu na kterou jste posílal ten link, tak ta evidentně žádné řetězce UCS4 znaků nepodporuje. Ona dokonce ani nezavádí datový typ pro Unicode code point, prostě je vrací jako int!
    Táto, ty de byl? V práci, já debil.
    14.3.2007 19:04 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Psal jsem o řetězcích UTF-16 znaků. Datový typ pro code point nezavádí, protože by se asi využíval strašně málo. Aplikací, které by potřebovaly pracovat s jednotlivými znaky UTF-32 asi nebude mnoho. Koneckonců, co byste s těmi UTF-32 znaky chtěl dělat jiného, než je konvertovat ze Stringu nebo charu a zase zpět?

    Mimochodem, které platformy nebo standardní knihovny pracují tak, že jako standardní znak platformy používají UTF-32 a řetězce se skládají ze znaků UTF-32?
    15.3.2007 09:58 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Prosím, máte vůbec soudnost??? UTF-16 je naprostý nesmysl, který je paměťově neefektivní (ASCII na 2 bajty) a současně velmi nevhodný pro zpracování textu (délka stringu neodpovídá počtu znaků). A jak jste proboha přišel na to že při zpracování textu nepotřebujete datový typ pro jeden unicode znak??? Co bych s nimi dělal? Samozřejmě strkal do proměnných, do vektorů, indexoval nimi hashe, cokoliv.. Nechápu jak můžete hájit názor že programátor nepotřebuje či nemá zpracovávat řetězec znak po znaku! Co nepotřebuje je akorát starat se o ty zku* UTF-16 surrogates! A UCS-4 (vy tomu říkáte UTF-32, dobrá, asi půjde o to samé) používá pro Unicode prakticky všechno krom Javy.
    $ grep "__WCHAR_TYPE__" /usr/lib/gcc/i386-redhat-linux/4.1.1/include/stddef.h
    #define __WCHAR_TYPE__ int
    typedef __WCHAR_TYPE__ wchar_t;
    
    Táto, ty de byl? V práci, já debil.
    15.3.2007 10:14 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    UTF-16 je naprostý nesmysl, který je paměťově neefektivní (ASCII na 2 bajty). A UCS-4 (vy tomu říkáte UTF-32, dobrá, asi půjde o to samé) používá pro Unicode prakticky všechno krom Javy.
    Takže UTF-16 se dvěma bajty na znak je paměťově neefektivní, ale UCS6 se 4 bajty na znak je správně?

    To, že má řetězcové API dále pracovat se znaky UTF-16, není vynález můj, ale doporučení konsorcia Unicode. Při zpracování textů vám je datový typ pro jeden znak celkem k ničemu. Text se kolekce znaků, řetězec, a pro práci s řetězci datový typ samozřejmě existuje (jmenuje se kupodivu String).
    15.3.2007 13:25 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    UCS4 je správné, protože je sice TAKY paměťově neefektivní, ale aspoň rychlé. UTF-16 je nekompatibilní s mnohem rozšířenějším a pro ukládání v externí paměti vhodným UTF-8, a navíc pomalé, píšou to v tom co jste linkoval. In a test run, for example, accessing UTF-16 storage as characters, instead of code units resulted in a 10× degradation. Žádné doporučení aby řetězcové API pracovalo s UTF-16 jsem tam nenašel. Můžete to citovat, prosím?
    Táto, ty de byl? V práci, já debil.
    15.3.2007 13:56 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Q: How about using UTF-32 interfaces in my APIs?

    A: Except in some environments that store text as UTF-32 in memory, most Unicode APIs are using UTF-16. With UTF-16 APIs the low level indexing is at the storage or code unit level, with higher-level mechanisms for graphemes or words specifying their boundaries in terms of the code units. This provides efficiency at the low levels, and the required functionality at the high levels.

    If its ever necessary to locate the nth character, indexing by character can be implemented as a high level operation. However, while converting from such a UTF-16 code unit index to a character index or vice versa is fairly straightforward, it does involve a scan through the 16-bit units up to the index point. In a test run, for example, accessing UTF-16 storage as characters, instead of code units resulted in a 10× degradation. While there are some interesting optimizations that can be performed, it will always be slower on average. Therefore locating other boundaries, such as grapheme, word, line or sentence boundaries proceeds directly from the code unit index, not indirectly via an intermediate character code index. [MD]

    Q: Doesn’t it cause a problem to have only UTF-16 string APIs, instead of UTF-32 char APIs?

    A: Almost all international functions (upper-, lower-, titlecasing, case folding, drawing, measuring, collation, transliteration, grapheme-, word-, linebreaks, etc.) should take string parameters in the API, not single code-points (UTF-32). Single code-point APIs almost always produce the wrong results except for very simple languages, either because you need more context to get the right answer, or because you need to generate a sequence of characters to return the right answer, or both.

    For example, any Unicode-compliant collation (See Unicode Technical Stdandard #10: Unicode Collation Algogrithm (UCA)) must be able to handle sequences of more than one code-point, and treat that sequence as a single entity. Trying to collate by handling single code-points at a time, would get the wrong answer. The same will happen for drawing or measuring text a single code-point at a time; because scripts like Arabic are contextual, the width of x plus the width of y is not equal to the width of xy. Once you get beyond basic typography, the same is true for English as well; because of kerning and ligatures the width of “fi” in the font may be different than the width of “f” plus the width of “i". Casing operations must return strings, not single code-points; see http://www.unicode.org/charts/case/ . In particular, the title casing operation requires strings as input, not single code-points at a time.

    Storing a single code point in a struct or class instead of a string, would exclude support for graphemes, such as “ch” for Slovak, where a single code point may not be sufficient, but a character sequence is needed to express what is required. In other words, most API parameters and fields of composite data types should not be defined as a character, but as a string. And if they are strings, it does not matter what the internal representation of the string is.

    Given that any industrial-strength text and internationalization support API has to be able to handle sequences of characters, it makes little difference whether the string is internally represented by a sequence of UTF-16 code units, or by a sequence of code-points ( = UTF-32 code units). Both UTF-16 and UTF-8 are designed to make working with substrings easy, by the fact that the sequence of code units for a given code point is unique. [AF] & [MD]

    Q: Are there exceptions to the rule of exclusively using string parameters in APIs?

    A: The main exception are very low-level operations such as getting character properties (e.g. General Category or Canonical Class in the UCD). For those it is handy to have interfaces that convert quickly to and from UTF-16 and UTF-32, and that allow you to iterate through strings returning UTF-32 values (even though the internal format is UTF-16). [MD]
    16.3.2007 09:40 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    To co jste zvýraznil jen doporučuje aby API byla nad celými řetězci a nepracovala znak po znaku. To že ony řetězce mají být v UTF-16 jste si vycucal z prstu. Ostatně hned další věta říká že UTF-8 je stejně dobré jako UTF-16, takže vzhledem k tomu že UTF-8 je nepochybně úspornější než UTF-16, dá se to chápat jako používejte UTF-8.

    Poslední odstavec říká že existují výjimečné nízkoúrovňové situace, kdy je vhodné pracovat s UTF-32. Takže máme dobré důvody používat UTF-32 (uvedené doporučení), a UTF-8 (jde o dominantní kódování v externí paměti). Pro UTF-16 žádné důvody nevidím (kompatibiltu s chybným designem jednoho inferiorního programovacího jazyka nelze považovat za rozumný důvod).
    Táto, ty de byl? V práci, já debil.
    16.3.2007 10:18 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Java používá odjakživa dvoubajtové kódování znaků, tak nebude kvůli zvětšení počtu znaků Unicode přes hranici 16 bitů přecházet na UTF-8. Výhoda UTF-16 oproti UTF-8 je ta, že pro většinu jazyků platí jedna kódovací jednotka = jeden znak. Před rozšířením Unicode nad 16 bitů to platilo pro úplně všechny znaky, a chyba nastala především v tom, že Unicode bylo původně 16bitové, a pak se rozšířilo. Což se v programovacím jazyce opravuje docela těžko, má-li být zachována zpětná kompatibilita.
    16.3.2007 11:05 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    > Java používá odjakživa dvoubajtové kódování znaků, tak nebude kvůli zvětšení počtu znaků Unicode přes hranici 16 bitů přecházet na UTF-8.

    Jistě, UTF-16 je cesta nejmenšího odporu.

    > Výhoda UTF-16 oproti UTF-8 je ta, že pro většinu jazyků platí jedna kódovací jednotka = jeden znak.

    Což platí pro UTF-8 také.

    > a chyba nastala především v tom, že Unicode bylo původně 16bitové, a pak se rozšířilo.

    Chyby se stávají. Ovšem s trochou snahy a odvahy se dají řešit, nikoliv jen obcházet. Když Java zavedla UCS-2, tvářila se že tím splnila dvě podmínky: 1) Podporuje všechny unicode znaky, 2) Každý znak zabírá ve stringu jednu pozici. Aplikace pak byly logicky implementovány tak že na to spoléhaly.

    > Což se v programovacím jazyce opravuje docela těžko, má-li být zachována zpětná kompatibilita.

    Naopak, šlo to velmi snadno. Stačilo triviálně změnit Javovský typ char z uint16_t na uint32_t. Obě podmínky by zůstaly zachovány. Pokud by to rozbilo nějakou starou aplikaci (např by spoléhala že cast na char usekne z intu horních 16 bitů), byla by aplikace velmi pravděpodobně napsána chybně, a zasloužila by si to. Vývoj Javy nesleduji, a opravdu jsem se domníval že přechod Unicode z 16 na 21 bitů vyřešili rozšířením datového typu char na 32 bitů. Poznámka že "char je přece napevno 16 bitů" byla pokus o sakrasmus, který mi bohužel nevyšel. Inu, jsem nepolepšitelný optimista když předpokládám že lidi kolem Javy mají občas rozum.

    Co se mi v těch textech o Javě ale OPRAVDU VELMI líbilo je jak tam zmiňují graphemes, such as Slovak letter "ch". To je fakt pobav, a klasická ukázka sebeklamu nebo rovnou aktivní demagogie. Tím že přešli na UTF-16 rozbili do té doby platný invariant že codepoint zabírá ve stringu vždy jednu pozici čímž vážně rozbili zpětnou kompatibilitu. Aby je developeři po právu za takovej kiks nezlynčovali, museli mamlasové z komitétu vymyslet nějaké zdůvodnění proč to vlastně nevadí. A tak kdesi vyštrachali že existuje něco jako dvojhlásky, jako "slovenské"(sic!) písmeno ch, a pro jeho detekci je třeba beztak koukat na string jako na celek, nikoliv jako na posloupnost unicode znaků, takže UTF-16 vlastně jen dělá něco co tu už stejně bylo. Hahahahahaha... Kdyby skutečně někomu záleželo na tom aby se dvouhláska ch chovala jako jeden element, jednoduše pro něj zavede Unicode codepoint, a je vymalováno. Ale protože to nikdo nepotřebuje, nestalo se tak, takže ch jako argument padá. Java je rozbitá, Q.E.D.

    Jo, a už mě ta debata vážně nebaví.
    Táto, ty de byl? V práci, já debil.
    16.3.2007 11:42 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Škoda jen, že to není text o Javě, ale oficiální FAQ Unicode, tedy doporučení pro všechny programovací jazyky. Pokud to nějaký jazyk dělá nějak jinak, je to jeho problém, Java se drží doporučení Unicode.

    Opravdu nechápu, proč vám tak chybí typ pro unicode znak. Porovnávat shodu řetězců, vyhledávat v řetězci, porovnat dva řetězce lexikograficky, převést řetězec z/do nějakého kódování – na to vše má Java metody ve standardní knihovně. A když někdo opravdu potřebuje pracovat se 32bitovými znaky unicode, může použít metody, které mu řetězec na tyhle znaky rozbije. Je nějaký další důvod, proč by programátor potřeboval pracovat s jednotlivými znaky místo s celými řetězci?
    16.3.2007 12:42 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    > Škoda jen, že to není text o Javě, ale... Pokud to nějaký jazyk dělá nějak jinak, je to jeho problém.

    Souhlas, Java si za problémy může sama.

    > Opravdu nechápu, proč vám tak chybí typ pro unicode znak... Je nějaký další důvod, proč by programátor potřeboval pracovat s jednotlivými znaky místo s celými řetězci?

    Efektivita. Char je literál co se vejde do registru nebo lokální proměnné, String je pointer na objekt, alokovaný někde na heapu. Z toho plyne řádový rozdíl ve výkonu.
    Táto, ty de byl? V práci, já debil.
    16.3.2007 13:41 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Pokud doporučení konsorcia Unicode považujete za chybu Javy, je to váš problém. A pokud vedle jednoho 32bitového typu potřebujete v programovacím jazyce ještě jeden 32bitový typ, který sice nikdo nepotřebuje, ale kdyby se náhodou rozhodl jej použít, bude to efektivní, je to taky váš problém. Je celkem zbytečné vědět, že jeden znak se vejde do registru procesoru, když absolutně nemáte představu, k čemu se znaky používají.
    16.3.2007 13:44 zde | skóre: 9 | blog: Linuch | Brno
    Rozbalit Rozbalit vše Re: Další Java-divnosti..
    Aha, tak jsme se konečně aspoň shodli na tom, v čem se neshodneme. Děkuji za diskusi a nashledanou.
    Táto, ty de byl? V práci, já debil.

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.