3. týden 6.3. Zadání DÚ 1 5. týden 20.3. Termín DÚ 1, Zadání DÚ 2 7. týden 3.4. Termín DÚ 2, Řešení DÚ 1, Zadání DÚ 3 9. týden 17.4. Termín DÚ 3, Řešení DÚ 2, Zadání DÚ 4 11. týden 1.5. Termín DÚ 4 13. týden 22.5. Řešení DÚ 3, Řešení DÚ 4 Termín DÚ: vždy úterý 9:00
termín: středa 23.3. 12:00 (poledne) Cíle: Multiplatformnost Návrh rozhraní Externí knihovny Asynchronní čtení souborů Zadání: Vytvořte objektovou knihovnu pro multiplatformní zastřešení platformně závislých knihoven pro asynchronní přístup k souborům. Knihovna musí zahrnovat alespoň POSIX AIO a Windows Asynchronous I/O.
#ifdef _MSC_VER... zavisly kod Windows #elif GNUG... zavisly kod POSIX #endif HANDLE f = CreateFile( f.txt, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS FILE_FLAG_OVERLAPPED, 0); OVERLAPPED o; memset(&o, 0, sizeof(overlapped)); o.hevent = CreateEvent(0, TRUE, FALSE, 0); o.offset = offs; ReadFile(f, buf, sz, &rsz, &o); nejaky_uzitecny_kod WaitForSingleObject(o.hEvent, INFINITE); CloseHandle(o.hEvent); CloseHandle(f);
int f = open( f.txt, O_RDONLY O_LARGEFILE, rights); aiocb a; memset(&a, 0, sizeof(aiocb)); a.aio_fildes = f; a.aio_offset = offs; a.aio_nbytes = sz; a.aio_buf = buf; a.aio_sigevent.sigev_notify = SIGEV_NONE; aio_read(&a); nejaky_uzitecny_kod if( aio_error( &a)!= EINPROGRESS) yyy // finished aio_suspend(&a, 1, 0); rsz = aio_return(&a); close(f);
Otevření souboru Začátek čtení Dotaz na připravenost výsledku Čekání na výsledek Na otevřeném souboru lze opakovat čtení Po uzavření souboru lze objekt znovu použít otevřením jiného souboru Operace v nevhodných stavech (např. čtení neotevřeného souboru) musí vyvolat výjimku Jakékoliv chybové nebo výjimečné stavy musí být zpracovány vyvoláním výjimky
Otevři soubor f.txt Začni číst z xx bajtů z offsetu yy do bufferu zz Dělej něco užitečného Občas se zeptej, jestli už je dočteno Počkej na výsledek Bonusy - funkčnost navíc za extra body: Rozhraní nenutící uživatele k používání sizeof() nebo dynamic_cast při použití strukturovaných bufferů Čekání na libovolný počet událostí
Jednotné OO rozhraní nevázané na konkrétní platformu Čistá a hezká syntaxe i sémantika Typy parametrů a návratových hodnot Ošetření výjimečných a chybových stavů Korektní stavové chování Bezwarningová zkompilovatelnost Včastnost odevzdání Omezení : Jen read Čekání jen na jednu událost Není nutné propagovat platformově závislé chybové kódy stačí vyvolání výjimky Není nutné podporovat různé způsoby otevření, práva, bitíky apod. stačí nejjednodušší otevřít soubor pro čtení (binárně) Není nutné ošetřovat jiné způsoby přerušení čtení (signály)
Pouze přes Grupík Vše v jednom.zip souboru do sloupečku DU1 Názvy zdrojáků (povinně): du1_aio.h du1_aio.cpp du1_main.cpp Neposílejte žádné makefile,.prj,.sln,.obj,.exe,.pdb a jakékoliv další vedlejší soubory za poslání nevhodného obsahu budou strhnuty body na začátek každého souboru vložte komentář typu // DU1-AIO.cpp // Karel Vomacka NPRG051 2010/2011
termín: středa 6.4. 12:00 (poledne) Cíle: Pokročilé použití šablon Politiky Zadání: Vytvořte objektovou knihovnu pro parsování argumentů předaných programu na příkazové řádce. Knihovna musí umožnit uživateli pomocí politik nastavit její detailní chování.
Podpora přepínačů bez parametrů tail --help Podpora přepínačů s typovaným parametrem (řetězce, číslo,...) make f makefile j 20 Podpora typovaných argumentů (řetězce, čísla,...) seq 10 20 1 Snadná rozšiřitelnost množiny typů, které knihovna umí naparsovat Bonus formátovaný výpis nápovědy programu
Konvence DOS/Windows dir /L /A:D POSIX ls s width=40 T 8 Java java cp. verbose:jni ds Co dělat při neznámém přepínači Vyhodit výjimku Ignorovat Považovat za argument Vypsat chybu a skončit
Co dělat s rozpoznanými přepínači Nechat být Odstranit z argv a aktualizovat argc Použití u různých knihoven, viz gtk_init, QApplication,... Co dělat při chybném formátu parametru přepínače nebo argumentu Vyhodit výjimku Vypsat chybu a skončit Co dělat s neočekávanými argumenty Ignorovat Vyhodit výjimku Vypsat chybu a skončit Parser musí umět pracovat s ANSI znaky (char) i s širokými znaky (wchar_t)
std::wstring file_name; size_t count; size_t size; bool verbose; std::vector<std::wstring> argumenty; inicializace knihovny pro konvenci POSIX s wchar_t - hodnotu parametru přepínače f nebo --file ulož do file_name - hodnotu parametru přepínače c nebo --count ulož do size - hodnotu parametru přepínače --size ulož do size - pokud se vyskytne přepínač v nebo -verbose ulož do verbose true - argumenty přidej do vektoru argumenty spusť parsování Příklad je pro konvenci POSIX, pro ostatní konvecne by mělo být použití obdobné. Kromě vektorů by mělo být možné vkládat argumenty do listů, množin apod.
enum prefix_type { KILO, MEGA, GIGA }; prefix_type prefix; inicializace knihovny pro konvenci POSIX - hodnotu parametru přepínače p nebo -prefix ulož do prefix spusť parsování Pozn.: hodnota parametru přepínače p resp. -prefix může být jedno z písmen K (KILO), M (MEGA) nebo G (GIGA). Je tedy nutné zajistit, aby se textová hodnota parametru přepínače převedla na správnou hodnotu výčtu. Funkci, která převede text na hodnotu daného typu musí samozřejmě napsat uživatel knihovny. Knihovna by ale měla poskytovat snadno použitelný mechanismus, jak integrovat uživatelské konvertory.
std::string log_file; inicializace knihovny pro konveci POSIX tak, aby rozpoznané přepínače odstraňovala z argv a argc a ignorovala nerozpoznané přepínače - hodnotu parametru přepínače l nebo --log ulož do log_file spusť parsování Po spuštění programu s parametry: -f soubor1 l soubor2 soubor3 a spuštění parsování, bude argc a argv stejné, jako kdyby byl program spuštěn s parametry: -f soubor1 soubor3
bool show_help; enum attribute_type { HIDDEN, DIRECTORY }; attribute_type attribute; inicializace knihovny pro konvenci DOS - pokud se vyskytne přepínač /H ulož do show_help true, nápověda k přepínači je Show help - hodnotu parametru přepínače /A ulož do attribute, nápověda k přepínači je File attribute. Supported types are:\nh Hidden\nD Directory zobraz nápovědu Výsledek: /H Show help /A:attribute File attribute. Supported types are: H - Hidden D - Directory Použití pro ostatní konvence by mělo být podobné a výstup by měl odpovídat zvolené konvenci.
Nezapomenout na možnost částečné nebo parciální specializace šablon, takže lze dosáhnout jiného chování pro různé typy, např. pro typ char a wchar_t. Prozkoumat, co je ve skutečnosti std::string, std::stream atd. a jestli toho nelze využít pro pohodlnou a jednotnou práci s různými typy znaků. Všechny kontejnery v STL umožňují zjistit typ prvků, které uchovávají pomocí členského typu value_type.
Kvůli různým typům znaku (char a wchar_t) budou pravděpodobně i samotné politiky šablonami. Pokud je potřeba specifikovat, že parametrem šablony je opět šablona, je třeba postupovat přibližně takhle: template <template <typename> class TPolicy, typename TChar> struct trida{ void do_something() { TPolicy<TChar>::do_something(); } }; template <typename TChar> struct politika { static void do_something() {} }; trida<politika, char> t; t.do_something();
Čistá a hezká syntaxe i sémantika Kvalita navrženého rozhraní knihovny Není třeba si lámat hlavu s tím, jak přesně se má knihovna chovat, jaké všechny formáty argumentů akceptovat a kolik mezer vypisovat. Zadání je schválně vágní, takže řešení mohou být značně variabilní. Návrh rozhraní jednotlivých politik Politiky musí skutečně implementovat dílčí kroky algoritmů a nikoliv jenom poskytovat konstanty apod., podle kterých se algoritmus bude řídit Ošetření výjimečných a chybových stavů Bezwarningová zkompilovatelnost (ideálně GCC i MSVC) Včastnost odevzdání Minimalizace duplicitního kódu (např. kód pro práci s řetězci by měl být napsaný pouze jednou tak, aby pracoval jak s char, tak s wchar_t
Odevzdání pouze přes Grupík Vše v jednom.zip souboru do sloupečku DU2 Součástí musí být soubor du2_main.cpp, který ukazuje použití knihovny, zbytek (tj. celou knihovnu) musí tvořit pouze hlavičkové soubory (vzhledem k použití šablon to jinak ani nepůjde). Jeden ze souborů knihovny musí mít jméno du2_parser.h, jehož includováním se zpřístupní všechny potřebné třídy a funkce knihovny. Posílejte pouze zdrojové soubory a neposílejte žádné makefile,.prj,.sln,.obj,.exe,.pdb a jakékoliv další vedlejší soubory za poslání nevhodného obsahu budou strhnuty body na začátek každého souboru vložte komentář typu // DU2-ARG.cpp // Karel Vomacka NPRG051 2010/2011
termín: středa 20.4 12:00 (poledne) Cíle: Vlastní kontejnery C++0x rvalue reference, move sémantika Zadání: Vytvořte chytrou hešovací mapu, která minimalizuje zbytečné kopírování pomocí C++0x rvalue referencí Třída musí podporovat standardní metody, musí umožnit uživatelům parametrizovat a nastavit její chování pomocí šablon
Vložení, smazání prvku, smazání všech prvků, základní iterátor operator [] s implicitním vložením prvku s default hodnotou operator= Poskytovat typy (key_type, value_type, data_type, iterator) Rehash při překročení load faktoru Klíčem jsou stadnardní typy (int, const char *, std::string, ) Vyhledávat v seřazeným poli Používat datové struktury jenom ze standardního stl Pokud to není vysloveně nutné, tak zamezit kopírování hešovací mapy (resp. jejich prvků)!
Typy key_type mapped_type Specifiká hešování parametrizován typem klíče hešovací funkci průměrný počet elementů v segmentu (bucket, slot) minimální počet segmentů porovnání dvou prvků (který je větší)
template<typename MapType, int SIZE> struct TestExample { void operator() () { MapType map; for ( size_t j = 0; j < SIZE; ++j ) map.insert( typename MapType::value_type(j,j) ); } };... TestExample<vase_implementace_mapy<int,int>,100> test; test(); template<typename key_type> struct hasher { enum { min_buckets = 8, bucket_size = 8 }; size_t operator()( const key_type& key ) const; bool operator()( const key_type& k1, const key_type& k2) const; }... TestExample<vase_implementace_mapy<int,int, hasher>,100> test; test();
template<typename MapType, int SIZE> struct TestPerformance { MapType create_another_map( const MapType& map ) { MapType new_map = map; for (size_t i = SIZE; i < 2*SIZE; ++i) new_map[i] = i; return new_map; } void operator() () { typedef std::vector<maptype> container_type; container_type container (SIZE, MapType()); for( size_t i = 0; i < SIZE; ++i) { MapType map; for ( size_t j = 0; j < SIZE; ++j ) map.insert( typename MapType::value_type(j,j) ); container[i] = create_another_map( map ); } } };
Podrobně popsat příklad II, proč se nepoužila RVO, kde se to zrychlilo a navrhnout komplexnější příklad ukazující zrychlení Naimplementovat swapy
C++0x VS2010 implicitne g++ -std=c++0x 1 test na 1 run - jinak hrozí zpomalení defragmentace paměti cache optimalizace kvalita hešovací funkce nebude předmětem hodnocení můžete použít již existující
Čistá a hezká syntaxe i sémantika Typy parametrů a návratových hodnot Ošetření výjimečných a chybových stavů Zrychlení oproti kopírující verzím Ošetření všech míst kde se zbytečně kopíruje Bezwarningová zkompilovatelnost Včastnost odevzdání
Pouze přes Grupík Vše v jednom.zip souboru do sloupečku DU3 Názvy zdrojáků (povinně): du3_map.h du3_main.cpp Posílejte pouze zdrojové soubory a neposílejte žádné makefile,.prj,.sln,.obj,.exe,.pdb a jakékoliv další vedlejší soubory za poslání nevhodného obsahu budou strhnuty body na začátek každého souboru vložte komentář typu // DU3-MAP.cpp // Karel Vomacka NPRG051 2010/2011
Termín: streda 4.5.2011 12:00 (poledne) Cíl: Sieťová komunikace via TCP Navrhnúť jednoduchý ale rozumný protokol dle specfikace Použiť multithreading (aspoň triviálne) Stačí jedna platforma Zadanie: Vytvorte uzly Seeder, Leecher a Tracker a navrhnite protokol dle specifikace tak, aby jeden Tracker vedel sprostredkovať viacerým Leecherom získanie súboru z viacerých Seederov. Očakáva sa, že jednotlivý Leecheri budu vymienať obsah aj medzi sebou.
Viditelnosť Každý Leecher vidí aspoň jeden Seeder Každý Leecher vidí Tracker Každý Leecher vidí aspoň zopár Leecherov Spolahlivosť V prostredí dochádza k výpadkom jednotlivých uzlov dočasne môžu všetky Seedery zmiznúť Tracker môže dočasne zmiznúť Leechery sa môžu objavovať a miznúť
FILE File je rozdelený na chunks rovnakej veľkosti Nodes si vymieňajú celé chunky atomická výmena Tracker Udržuje informácie o tom kto má aké chunks Leecher sa Trackeru dotazuje, kde môže získať chunks, ktoré mu chýbaju Seeder odpovedá a poskytuje Leecherom data Leecher poskytuje data iným Leecherom a sám sa snzí získať celý súbor. Tracker File File Leecher Leecher Seeder Seeder Seeder
Udržuje databázu rozdelenia chunkov v prostredí Nemusí mať explicitné spojenie so Seedermi je to ale vhodné, aby zbytočne nešíril nedostupné Seedery ako zdroj Trackovaný súbor je špecifikovaný v.torrent súbore nasledovne File name e.g. TheMovie.avi [null terminated string] File attributes Size [8B], hash [depends], #of chunks [8B] #chunk size [4B], chunk hash list [depends] Hash == (SHA1/CRC32, cokolvek) Seeder list URL:Port URL [null terminated string] PORT [2B]
Medzi Leecherom a Trackerom vznikne session ktorá by mala byť perzistetnou po určitú dobu (timeout) Tracker môže TCP spojenie ukončiť ak sa mu nezdá dosť aktívne po nejakú dobu Leecher môže ukončiť spojenie ak ho nepotrebuje (ale session NIE) Rozlišovať session a tcp spojenie Tracker prideluje IDčka Leecherom a Seederom Leecher sa musí u Trackeru zaregistrovať Správy HELO a BYEBYE - vznik session a ukončenie session Leecher Trackeru oznámi aké chunky má už stiahnuté Správa IHAVE navrhnite rozumne a nie tak bajvoko Leecher sa Trackera pýta na zdroje dát Správa INEED Leecher sa môže opýtať na konkrétne chunky ktoré chce Leecher môže špecifikovať koľko zdrojov chce Leecher môže nechať všetko na Trackera zistenie ktoré chunky nemá atď
Leecher môže Trackeru oznámiť, že niektoré zdroje sú preňho nedostupné Správa TOOFAR Tieto zdroje Tracker Leecherovi už nebude posielať Správa RESET zresetuje databázu nedostupných uzlov Leecher by mal Trackeru oznámiť ktoré chunky sa mu podarilo získať viz IHAVE Leecher sa smie pripájať len na obmedzený počet Seederov Toto reguluje Tracker pridelovacou politikou
Leecher sa môže pripojiť na Leechera/Seedera a žiadať chunky Pripojenie tiež via Session HELLO, BYEBYE Leecher oznami protajšku čo má k dispozícii IHAVE zoznam chunkov INEED zoznam požiadaviek GET ktorý chunk chce PUT posiela chunk na vyžiadanie Leecher/Seeder by mal zvládať rozumný nápor a rovnomerne obsluhovať všetky požiadavky Posielať len jednému a potom dalšiemu sa nepovažuje za rovnomerné
Implementácia Leechera, Seedera a Trackera Špecifikácia obsahu protokolu Torrent file (náš testovací súbor bude veľký) Rozumný návrh komunikácie, s prihliadnutím na nespolahlivost prostredia
Rozumná politika výberu zdrojov pre Leechra Aby nedostali všetci Leechri ten isty Seeder a ten sa zosype Parametrizovatelnost Multiplatformovost