3. týden 10.3. - Kontejner Zadání DÚ 1 5. týden 24.3. Exception safe policy Termín DÚ 1, Zadání DÚ 2 7. týden 7.4. SAX C opendir Termín DÚ 2, Řešení DÚ 1, Zadání DÚ 3 9. týden 21.4. Multithreaded network Termín DÚ 3, Řešení DÚ 2, Zadání DÚ 4 11. týden 5.5. -nekoná se Termín DÚ 4 13. týden 19.5. Řešení DÚ 3 a DÚ 4, rozdávání zápočtů Termín DÚ: vždy středa 12:00
termín: středa 24.3. 12:00 (poledne) vytvořit kontejner dvourozměrná matice dopředné (forward) iterátory přes sloupce i řádky velikost fixní, určená parametry konstruktoru lze přiřazení včetně rozměrů typ jakýkoliv, který lze použít v STL kontejnerech (vector) norma: default constr, copy constr, operator=, destr) neřešit metody pro zvětšování a zmenšování konstantnost vs. nekonstantnost bonus (max +2 body): indexace přes řádky i sloupce a[x][y] (a.rows()[x][y] a.cols()[x][y]) bonus (max +3 body): bezpečné řešení v debug módu odchytávat všechny nedefinované akce
typedef matrix< int> my_matrix; int cnt = 100; void f1( my_matrix::cols_t::value_type::reference x) { x = ++cnt; void f2( my_matrix::cols_t::reference r) { for_each( r.begin(), r.end(), f1); void f3( my_matrix::rows_t::value_type::reference x) { cout << x << " "; void f4( my_matrix::rows_t::reference r) { for_each( r.begin(), r.end(), f3); cout << endl; int main( int argc, char ** argv) { my_matrix a( 3, 4, 0); for_each( a.cols().begin(), a.cols().end(), f2); for_each( a.rows().begin(), a.rows().end(), f4); procházení prvků sloupce procházení po sloupcích procházení po řádkách
forward iterator Can be default-constructed X a; X() Can be copied and copy-constructed X b(a); b = a; Accepts equality/inequality comparisons; equal iterators imply the same element is pointed a == b a!= b Can be dereferenced (when not null) *a a->m Can be incremented (when not null) ++a a++ *a++
bude probíráno zítra na přednášce Standard algorithms use members of the iterator_traits class to determine the characteristics of the iterators. For every iterator type, a corresponding specialization of iterator_traits class template with at least the following member types shall exist: difference_type type to express the result of subtracting one iterator from another value_type the type of the element the iterator can point to pointer the type of a pointer to an element the iterator can point to reference the type of a reference to an element the iterator can point to iterator_category... forward_iterator_tag
vytvořené třídy musí být kompatibilní s STL kontejnery a algoritmy všechny vyžadující forward iterator - for_each pro pomocné třídy cols/rows vytvořit: typy: iterator, reference, value_type metody: begin(), end(), size(), bonus: op[] iterátory: 5 typů, *, ->, ++, =, == celkem 4 pomocné kvazi-kontejnery: řádky, sloupce, prvky v řádku, prvky v sloupci
problém: kvazikontejner vrací iterátor, ten má svoji hvězdičkou zpřístupnit něco, co v té matici nemusí být (typicky sloupec) možné řešení: * na iterátoru vrátí hodnotou pomocnou na na místě sestrojenou třídu normálně * vrací T& tady nás k tomu sice nic nenutí musí se to ale chovat podobně pozor: na iterátoru musí být -> (požadavek normy) běžné řešení: vrátí ukazatel na typ s příslušnými metodami není ale na co vrátit * nebo: vrátí jinou třídu s přetíženým operátorem -> jiná třída - proxy na sloupec
včasnost za nedodržení termínu body prudce dolů přeložitelnost přeložitelné bez chyb a (pokud možno) warningů kompatibilní s vzorem použití (rozhraní je pevné) multiplatformnost nezávislost na OS, bitovosti, překladači - vyzkoušejte i gcc32/vs64 stabilita rozhodně vyzkoušejte všechna možná přípustná data a typy kultura kódu pravidla, moudra, dobré zvyky, udržovatelnost, estetika, čitelnost odevzdávací formality a konvence názvy a struktura souborů, komentáře
indexace přes řádky i sloupce max +2 body a[x][y] (a.rows()[x][y]) a.cols()[x][y] bezpečné řešení v debug módu max +3 body odchytávat všechny nedefinované akce du_assert(e) if( e == 0) chyba v debug verzi du_assert vypíše lokaci a skončí v release verzi (definováno makro DU_NDEBUG) nedělá nic - odletí
v du1.zip najdete 4 soubory du1test.cpp kód používající vaše řešení - neměňte - zachovat rozhraní! můžete (velmi doporučeno!) přidat vlastní testy du1debug.hpp definice pro bonus - du_assert du1matrix.cpp, du1matrix.hpp kód a hlavičkový soubor vašeho řešení soubory nepřejmenovávejte na začátek každého souboru vložte komentář typu // DU1matrix.cpp // Karel Vomacka NPRG051 2009/2010 vaše řešení vložte do Grupíčku - neposílejte emailem! správné soubory do správných sloupečků!
termín: středa 7.4. 12:00 (poledne) vytvořte exception-safe merger slévač odolný vůči výjimkám merger = slévač dat množiny streamů stream může být cokoliv soubor, string, webový stahovač... cokoliv co poskytuje data předpoklad - data setříděná vzhledem k operaci < na value_type typ dat může být cokoliv char, int, string, zlomky, obrázky,... cokoliv co se dá strčit do kontejneru a má operaci < šablona řízená politikou exception safety na zítřejší přednášce! strong safety - objekt se uvede do původního stavu
struct int_istringstream_policy { typedef istringstream stream_type; typedef int value_type; static void stream_open( stream_type & s, const string & p)... static void stream_close( stream_type & s)... static bool stream_get( stream_type & s, value_type & v)... ; příklad jednoduché politiky typ streamu a hodnot metody streamu template< typename policy, typename arg_type> void test( const arg_type & arg) { try { typename policy::stream_type s; policy::stream_open( s, arg); typename policy::value_type v; while ( policy::stream_get( s, v) ) { cout << v << endl; policy::stream_close( s); catch ( const std::exception & e) { cout << e.what() << endl; zadám politiku (stream), arg_type se odvodí z parametrů tajuplné argumenty streamu řetězec s čísly stream si prostě otevřu a přečtu test streamu string vracející int test< int_istringstream_policy>( "1 2 3 4");
struct int_istringstream_policy { typedef istringstream stream_type; typedef int value_type; static void stream_open( stream_type & s, const string & p) { s.str( p); if( s.bad() ) throw exception( "Open failed"); static void stream_close( stream_type & s) { s.clear(); if ( s.bad() ) throw exception( "Close failed"); static bool stream_get( stream_type & s, value_type & v) { s >> v; if ( s.fail() ) { if ( s.eof() ) return false; throw exception( "Get failed"); return true; ; příklad jednoduché politiky nadefinované typy metody streamu
template <...> struct merge_policy { typedef... stream_type; typedef... value_type; static void stream_open( stream_type & s,...)... static void stream_close( stream_type & s)... static bool stream_get( stream_type & s, value_type & v)... ; merger_policy typ streamu a hodnot metody streamu template< typename policy, typename arg_type> void test( const arg_type & arg) { try { typename policy::stream_type s; policy::stream_open( s, arg); typename policy::value_type v; while ( policy::stream_get( s, v) ) { cout << v << endl; policy::stream_close( s); catch ( const std::exception & e) { cout << e.what() << endl; zadám politiku (stream), arg_type se odvodí z parametrů tajuplné argumenty streamu merger: množina vstupů stream si prostě otevřu a přečtu test politiky merge_policy na streamech stringů vracejících int test< merge_policy<...> >(... ); mergovat více streamů mergovat více streamů jak je zadám?
struct int_istringstream_policy { typedef istringstream stream_type; typedef int value_type; static void stream_open( stream_type & s, const string & p)... static void stream_close( stream_type & s)... static bool stream_get( stream_type & s, value_type & v)... ; tyto typy a metody může použít implementace merge_policy merge_policy se opět chová jako stream politika - typy, metody vector< string> data; data.push_back( "1 3 5 7"); data.push_back( "2 4 6"); data.push_back( "3 4 5"); 3 streamy test< merge_policy< int_istringstream_policy> >( make_pair( data.begin(), data.end())); slije ty 3 streamy
politika parametrizovaná vstupními streamy typy převezmu ze vstupů inicializace - posloupnost vstupních streamů template< typename input_policy> struct merge_policy { typedef merge_stream< input_policy> stream_type; typedef typename input_policy::value_type value_type; template< typename it> static void stream_open( stream_type & s, const pair< it, it> & p); static void stream_close( stream_type & s); static bool stream_get( stream_type & s, value_type & v); ; problém: politika -> neinstanciuje se kde si schovám data? (vektor vstupů, buffer pro výstup) get bude vracet slitá data šablona libovolné iterátory
template< typename policy, typename arg_type> void test( const arg_type & arg) { try { typename policy::stream_type s; policy::stream_open( s, arg); typename policy::value_type v; while ( policy::stream_get( s, v) ) { cout << v << endl;... instanci si vytvoří uživatel - test musím vyrobit třídu merge_stream parametrizovanou streamem template< typename input_policy> struct merge_policy { typedef merge_stream< input_policy> stream_type; typedef typename input_policy::value_type value_type; template< typename it> static void stream_open( stream_type & s, const pair< it, it> & p); static void stream_close( stream_type & s); static bool stream_get( stream_type & s, value_type & v); ; volá metody stream_type
strong exception safety close a destruktory nevyvolávají výjimku cokoliv jiného (vč. konstruktoru) může vyvolat výjimku strong safety předpoklad: strong safety streamové politiky transakční chování v případě výjimky se stream uvede do původního stavu žádnou výjimku nezatajit po výjimce v get možné další volání vždy buď úspěšné čtení nebo výjimka možné zdroje výjimek otevření (soubor neexistuje) čtení dat (někdo utrhl kabel, špatný formát dat) kopírování dat při návratu! (došla paměť při manipulaci s value_type) práce s vlastními kontejnery...
Upřesnění chování pro zavírání streamů Když close vyvolá výjimku, lze ji meli ignorovat, není třeba ji propagovat dal, ale rozhodně musí být dokončeny closy ostatních vstupů. Vstup, jehož close vyvolal výjimku, se považuje za uzavřený.
politikou řízený merger stream definuje typy stream_type a value_type funkce stream_open, stream_close, stream_get vytvořte politiku merger je sama streamem parametrizovaná streamem (politikou) get vrací slitá data ze vstupů protokol (konstr) -open -get* -close -(destr) korektní volání -> korektní chování nekorektní volání -> jakékoliv chování strong exception safety strong safety streamové politiky -> transakční chování mergeru
ekvivalentní DÚ1 du2.zip du2test.cpp kód používající vaše řešení - neměňte - zachovat rozhraní! můžete (velmi doporučeno!) přidat vlastní testy, politiky,... du2test_all.cpp - detailní testování, výjimky du2policy.cpp, du2policy.hpp soubory nepřejmenovávejte na začátek každého souboru vložte komentář typu // DU2policy.cpp // Karel Vomacka NPRG051 2009/2010 řešení do Grupíčku - neposílejte emailem! kritéria hodnocení použití politik exception safety včasnost, přeložitelnost, multiplatformnost, stabilita, kultura kódu
termín: středa 21.4. 12:00 (poledne) zpracovat data podle rozparsovaného XML souboru cíle: použití externích knihoven C callbacks multiplatformnost libxml http://xmlsoft.org/ nepoužívejte jiné knihovny (xalan, saxon, libxml++,...) SAX2 nepoužívejte ani DOM ani XmlReader ani SAX(1) podrobněji o parserech a SAX na zítřejší přednášce internacionalizace není cílem DÚ pro účely DÚ xmlchar char
<?xml version="1.0"?> <AA> <BB> <DU3FILE>dir1/dir2/file.txt</DU3FILE> </BB> <CC> <DD> <DU3INCLUDE>dir3\xml2.xml</DU3INCLUDE> </DD> </CC> </AA> <?xml version="1.0"?> <EE> <DU3FILE>dir4\dir5</DU3FILE> </EE> soubor různé konvence include adresář
[AA/BB/file.txt] radka1 souboru [AA/BB/file.txt] radka2 souboru... [AA/BB/file.txt] posledni radka souboru [AA/CC/DD/EE/otherfile1.txt] radka1 souboru... [AA/CC/DD/EE/otherfile2.txt] radka1 souboru... každý nalezený soubor se vypíše s XML prefixy a jménem souboru (na každé řádce)
na příkazové řádce jméno souboru - XML libovolné tagy / struktura zajímavé tagy: <DU3FILE> název souboru nebo adresáře (s cestou) - vypsat <DU3INCLUDE> název XML souboru nebo adresáře (s cestou) - includovat oddělovače adresářů platformově nezávislé - '/', '\' jméno adresáře operace se provede na všechny soubory v adresáři že to je adresář musíte zjistit sami standardní výstup řádky souborů prefixované XML cestou a názvem souboru práci s adresáři norma neřeší řešení musí fungovat na VS a GCC definovaná makra _MSC_VER a GNUG
ekvivalentní předchozím DÚ řešení do Grupíčku kritéria hodnocení standardní: včasnost, přeložitelnost, stabilita, kultura kódu speciálně - interoperabilita C / C++ Win / Linux minimalizace a izolace platformově závislých částí
termín: středa 5.5. 12:00 (poledne) distribuovaná vícevláknová faktorizace cíle: síťování multithreading vlákna linux: pthreads (POSIX threads) windows: WinAPI lze multiplatformní: Boost nepoužívejte jiné knihovny (TBB,...)
typedef long long t_du4long; typedef vector<t_du4long> t_du4factors; void factorize( t_du4long x, t_du4factors& v) { t_du4long limit = sqrt(x); for( t_du4long i = 2; i <= limit; ++i) { while( x % i == 0) { v.push_back( i); x /= i; if( x == 1) return; v.push_back( x); void fac_all( const vector<t_du4long>& vx, vector<t_du4factors>& vv) { vector<t_du4long>::const_iterator vi; for( vi = vx.begin(); vi!= vx.end(); ++vi) { t_du4factors v; factorize( *vi, v); vv.push_back( v); int main( int argc, char** argv) { vector<t_du4long> vx; vx.push_back( 1234567890123456789LL); vx.push_back( 2LL * 3 * 5 * 7 * 11 * 13 * 17 * 23); vector<t_du4factors> vv; fac_all( vx, vv); return 0; worker: faktorizace jednoho čísla dispečer: faktorizace balíku čísel
Worker Worker Worker Worker thread pool Worker thread Worker thread Worker thread Comm thread 1 2 3 2 3... Dispečer zprávy: 1: registrace 2: zaslání balíčku (vektor čísel) 3: odpověď (vektor vektorů faktorů)
worker workeři se sami přihlašují k dispečeru adresu a port dostanou jako parametr worker ví kolik má mít pracovních vláken dispečeru to ale neříká jedno vlákno workera je vyhraženo pro komunikaci s dispečerem ostatní vlákna nekomunikují worker distribuuje přidělený balíček vláknům po spočítání celého balíčku vrátí odpověď dispečer poslouchá na přihlašovacím portu metoda pro příjem práce (velký vektor čísel) rozděluje balíčky workerům, přijímá odpovědi velikost balíčku konstanta workeři můžou přibývat během práce nemusí řešit nespolehlivost workerů
multithreadalita thread pool není nutná platformová nezávislost faktorize - krásně nepředvídatelná úloha doba výpočtu se liší 100000x nelze ji nijak odhadnout ze vstupu, nelze staticky rozdělit síťování big endians / little endians transportní formát nezávisle na platformě žádné send( &number); nadefinujte si vlastní protokol připojení, žádost, odpověď není nutné řešit timeouty, ztrátu uzlu,... posílání práce (a odpovědí) po balíčkách worker skončí po uvolnění od dispečera
disp_main.cpp dispatch.exe dispatch.hpp dispatch.cpp common.hpp common.cpp worker.cpp worker.hpp worker_main.cpp worker.exe
class Worker { public: Worker( std::string dispatcher, int port, int threads = 4) { private: void Worker::factorize( t_du4long number, /*out*/ t_du4factors& factors); ; class Solver { public: Solver( int chunk = 30) : chunk_(chunk) { void factorize( const std::vector<t_du4long>& numbers, /*out*/ std::vector<t_du4factors>& factors); private: int chunk_; // additional declarations ; tuhle funkci dostanete neměnit! tuhle funkci udělat pořádně int main( int argc, char** argv) { Solver s(5); vector<t_du4long> numbers; numbers.push_back( 1234567890123456789LL); numbers.push_back( 2LL * 3 * 5 * 7 * 11 * 13 * 17 * 23); vector<t_du4factors> factors; s.factorize( numbers, factors);
řešení do Grupíčku 6 souborů du4common.*, du4dispatch.*, du4worker.* kritéria hodnocení standardní: včasnost, přeložitelnost, stabilita, kultura kódu speciálně efektivní využití vláken nezávislost síťové komunikace na reprezentaci dat