======= TINY: Jednohubky =======
==== 00 – Formátovaný zápis do proudu ====
V této jednohubce budete mít za úkol naimplementovat jednoduchou funkci,
''write_stats'', která bere dva argumenty, sadu dat a výstupní proud,
a do výstupního proudu zapíše 3 statistické údaje o datech: minimum,
maximum a průměr.
Údaje musí být zapsány ve specifickém formátu, například pro vstupní data
"1.23, 5.44, -23" by výstup vypadal takto:
min: -23.00
max: 5.44
mean: -5.44
//Všimněte si, že čísla jsou vždy vypsaná se dvěma desetinnými čísly.//
Projekt s testy najdete {{:courses:b6b36pcc:ukoly:tiny-00.zip|zde}}.
Do Brute odevzdávejte pouze Váš soubor ''tiny-00.cpp'' s vaší implementací
funkce ''write_stats''.
\\
=== Rady ===
Formátovací manipulátory, které budete potřebovat, najdete v jedné ze dvou
hlaviček:
* [[http://en.cppreference.com/w/cpp/header/iomanip|iomanip]]
* [[http://en.cppreference.com/w/cpp/header/ios|ios]]
Zároveň vás může zajímat šablona
[[https://en.cppreference.com/w/cpp/types/numeric_limits|numeric_limits]],
přes kterou můžete získat informace o největší možné hodnotě typu a další
podobné informace.
==== 01 – Kopie a reference ====
V této jednohubce dostanete rozpracovaný kód implementující dvě přetížení
funkce ''pluralize'', specificky
* ''std::string pluralize(std::string const& str);''
* ''std::vector pluralize(std::vector const& str);''
Jak název napovídá, úkol této funkce je převést předané slovo, případně
vektor slov, na jejich množné číslo. V kódu který máte je ovšem chyba,
takže část testů neprochází, a vaším úkolem je změnit kód který dostanete
tak, aby všechny testy procházely.
Projekt s testy najdete {{:courses:b6b36pcc:ukoly:tiny-01.zip|zde}}.
Do Brute odevzdávejte pouze zazipovaný soubor ''tiny-01.cpp'' s vašimi
změnami.
\\
=== Rady ===
Tento úkol si můžete udělat velmi těžký, nebo velmi jednoduchý. Proto
vám doporučujeme si před hledáním chyby v kódu pustit testy a rozmyslet
si, co vidíte na výstupu.
==== 02 – Práce s dynamicky alokovanou pamětí ====
V této jednohubce znovu dostanete již hotový kód, ale na rozdíl od minulé
jednohubky všechny testy procházejí. To ovšem neznamená, že je s ním vše
v pořádku -- jak název napovídá, obsahuje chybu práce s dynamicky
alokovanou pamětí.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-02.zip|zde}}.
**Poznámka k implementaci:** funkcionalita funkce ''summarize_data'' je
popsána uvnitř hlavičky ''tiny-02.hpp'' anglicky. Pro jistotu ji zde
uvádíme i česky:
* Funkce ''summarize_data'' vrací statistiky pro každý validní řádek uvnitř předaného proudu. Nevalidní řádky jsou přeskočeny. Samotný řádek začíná číslem **n**, které určuje kolik čísel na řádku následuje. Následná čísla musí být z rozsahu [0, 255].
\\
=== Rady ===
Pokud jste na Linuxu, již mnohokrát zmiňovaný
[[http://valgrind.org/|Valgrind]] vám řekne k jaké chybě dochází a kde.
Pokud jste na Windows, doporučujeme [[http://drmemory.org/|Dr. Memory]],
který funguje zhruba stejně jako Valgrind. Pokud používáte aktuální verzi
OS X, Valgrind vám bohužel nebude fungovat, budete tedy muset použít
o něco komplikovanější nástroj jménem
[[https://clang.llvm.org/docs/AddressSanitizer.html|AddressSanitizer]].
==== 03 – Život objektů ====
Poučen problémy v minulé jednohubce se programátor rozhodl opravit kód
''summarize_data'' tak, aby ke stejné chybě již nemohlo dojít. Vytvořil
si tedy třídu ''fixed_array'', která za alokované pole zodpovídá a vždy
ho správně uvolní. Bohužel se to zcela nepovedlo a na vás je, abyste
to opravili.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-03.zip|zde}}.
Též trochu změnil formát výstupu, protože si uvědomil, že když se špatné
řádky prostě vypustí, tak není možné zpětně zjistit, které řádky nebyly
platné. Nyní se tedy pro neplatné řádky vrací statistika, která říká, že
na řádku bylo ''std::numeric_limits::max()'' prvků.
\\
=== Rady ===
Pokud se vám kompilátor snaží poradit, je dobrý nápad mu naslouchat.
==== 04 – Kopie a přesuny ====
V této jednohubce bude vaším úkolem doplnit funkční kopírovací a
přesunující operace pro jednoduchý binární vyhledávací strom.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-04.zip|zde}}.
\\
=== Rady ===
Připomeňte si obsah odpovídající cvičení.
==== 05 – Operátory ====
V této jednohubce si vyzkoušíte přetěžování operátorů pro třídu.
Specificky se jedná o třídu ''pjc::complex'' a matematické operátory
''+'', ''-'' a ''*'' (pouze v binární variantě). Specificky chceme, aby
šly sčítat (respektive odčítat nebo násobit) dvě instance třídy
''pjc::complex'' nebo instance třídy ''pjc::complex'' s ''double''.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-05.zip|zde}}.
Do Brute tentokrát odevzdejte i vámi změněnou hlavičku ''tiny-05.hpp''.
\\
=== Rady ===
Pokud si nepamatujete jak fungují dané operace nad komplexními čísly,
[[https://cs.wikipedia.org/wiki/Komplexn%C3%AD_%C4%8D%C3%ADslo#Operace_s_komplexn%C3%ADmi_%C4%8D%C3%ADsly|wikipedie
poradí]].
==== 06 – Nevirtuální a virtuální rozhraní ====
V této jednohubce vás čeká modifikace již existující virtuální hierarchie tříd.
Specificky se jedná o hierarchii různých generátorů náhodných čísel a
vaším úkolem bude do ní doplnit sběr různých statistik:
* Nejmenší/největší vygenerovaný ''int'', respektive ''double''
* Počet vygenerovaných ''int'', ''double'' čísel
* Počet vygenerovaných ''bool'', včetně toho, kolik jich bylo pravdivých a kolik nepravdivých
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-06.zip|zde}}.
Do Brute tentokrát odevzdejte i vámi změněnou hlavičku ''tiny-06.hpp''.
\\
=== Rady ===
Existují dva způsoby, jak tuto jednohubku vyřešit. Jeden je pracnější,
zabere vám delší dobu, ale nemusíte u něj vůbec přemýšlet. Alternativně
můžete použít idiom, kterému se říká Nevirtuální rozhraní (NVI -- NonVirtual
Interface), který umožňuje předkovi (rozhraní) vynutit, aby byly dodrženy
invarianty během volání poděděných metod.
NVI je implementace návrhového vzoru "Template Method" (šablona,
šablonová metoda), specifická pro C%%++%%. Bohužel se nám nepovedlo najít dobrý
text vysvětlující specificky NVI v češtině, ale
[[https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface|WikiBooks]]
obsahuje dobré vysvětlení v angličtině.
==== 07 – Simulace kovariantních návratových typů s chytrými ukazateli ====
Jak jsme si ukazovali na cvičení, v C%%++%% nelze kombinovat kovariantní
návratové typy s chytrými ukazately, jako je například ''std::unique_ptr''.
Nicméně, chytrou kombinací nevirtuálního rozhraní, schovávání, virtuálního
rozhraní a boilerplate, se dá kovariance simulovat.
V této jednohubce budete znovu pracovat s hierarchií tříd které generují
náhodná čísla a vaším úkolem bude doplnit metodu ''clone'', která vrací
příslušně konkretizovaný ''std::unique_ptr'' a zároveň se chová polymorfně.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-07.zip|zde}}.
Do Brute odevzdejte i vámi změněnou hlavičku ''tiny-07.hpp''.
\\
=== Rady ===
Je jasné, že metoda ''clone'' nemůže být virtuální, ale pro její správné
chování potřebujete virtuální polymorfismus. Jinak řečeno, budete muset
těch metod implementovat více.
==== 08 – Jednoduchá šablonová funkce ====
V této jednohubce si napíšete jednoduchou šablonovou funkci ''clamp''.
Tato funkce se v C%%++%%17 stala součástí standardní knihovny, ale protože
v tomto předmětu používáme tento semestr stále ještě C%%++%%14, budeme ji
implementovat my.
Funkce ''clamp'' má dvě přetížení
* ''T const& clamp(T const& value, T const& low, T const& high)''
* ''T const& clamp(T const& value, T const& low, T const& high, Compare cmp)''
které vrací ''low'' pokud ''value'' je menší než ''low'', ''high'' pokud
''value'' je větší než ''high'' a jinak ''value''. Jinak řečeno, ''value''
je omezeno do rozsahu ''[low, high]''. První overload předpokládá, že
''T'' je porovnatelné pomocí operátoru ''<'', druhý overload pak bere
vhodný komparátor jako 4. argument.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-08.zip|zde}}.
Do Brute odevzdejte vaši hlavičku ''tiny-08.hpp''.
\\
=== Rady ===
Není potřeba implementovat obě funkce stejně, můžete implementovat jednu
voláním druhé. K tomu se vám bude hodit obsah hlavičky
[[https://en.cppreference.com/w/cpp/header/functional|functional]].
\\
=== Další ===
K této jednohubce vám navíc nabízíme dvě otázky k zamyšlení:
* Pokud uživatel předá parametry ve špatném pořadí, může dostat špatný výsledek. Toto se dá opravit, pokud funkci přejmenujeme((A změníme implementaci tak, aby odpovídala novému jménu)). Jaké jméno by to bylo?
* ''const int& clamped = clamp(value, 0, 255);'' může vést k chybě. K jaké? Jde to rozumně opravit?
==== 09 – Jednoduché metaprogramování ====
V této jednohubce se naposled vrátíme k naší implementaci ''vector'' ze
cvičení. Poslední, co jsme s ním dělali, byla optimalizace metody
''push_back(Iterator, Iterator)'' dle typu iterátoru, kterou dostala.
V této jednohubce budeme podobně optimalizovat zvětšování (a kopírování)
vektoru v závislosti na typu, pro který je náš ''vector'' instanciovaný.
Specificky to znamená, že budeme rozlišovat 3 druhy typů,
* Triviálně kopírovatelné typy
* Typy, které mají přesunující přiřazení označené jako ''noexcept'' a nejsou triviálně kopírovatelné
* Ostatní typy
a budeme se k nim chtít chovat jinak, když budeme rozšiřovat pole uvnitř
vektoru. Specificky, triviálně kopírovatelné typy chceme kopírovat pomocí
[[https://en.cppreference.com/w/cpp/string/byte/memcpy|memcpy]],
typy, které nejsou triviálně kopírovatelné, ale nemohou vyhodit výjimku
při přesunujícím přiřazení, chceme opravdu přesunout a typy, které výjimku
vyhodit mohou, chceme prostě zkopírovat.
Projekt s implementací a testy najdete
{{:courses:b6b36pcc:ukoly:tiny-09.zip|zde}}.
Do Brute odevzdejte hlavičky ''array.hpp'', ''vector.hpp'' a případné jiné
hlavičky které jste vytvořili.
**K zjištění, jestli je typ triviálně kopírovatelný používejte
''pjc::is_trivially_constructible'' z ''pjc-traits.hpp'', a ne
''std::is_trivially_constructible''.**
\\
=== Rady ===
Pro implementaci tohoto úkolu doporučujeme použít SFINAE (viz přednáška),
a ne tag dispatch, který byl použit na cvičení.
Jestli přesunující přiřazení daného typu je noexcept se dá zjistit pomocí
traitu [[https://en.cppreference.com/w/cpp/types/is_move_assignable|is_nothrow_move_assignable]]
ze standardní knihovny.
\\
=== Další ===
Triviálně kopírovatelné typy jsou typy s triviálním kopírovacím
konstruktorem a přiřazením. Méně kruhově definováno, jsou to typy
u kterých je volání kopírovacích operací ekvivalentní se zkopírováním
jejich bitové reprezentace((Toto striktně řečeno není pravda pro typ
''trivially_copyable_tracker'', proto jsme zavedli
''pjc::is_trivially_constructible'' trait a specializovali ho pro tento
typ.)).
Důvod, proč nechceme přesouvat typy, které mohou vyhodit výjimku je
poskytnutí tzv. silné záruky. Detaily jsou v přednášce "Exception Safety",
hrubý nástin pak je, že pokud dojde k chybě během zvětšování vektoru,
tak se silnou zárukou zůstanou původní prvky zachovány a nepřijdeme o data.