/* Jan Dudziec
 * Grupa T6TIZ
 *
 * Poniższy listing ma za zadanie pokazać użycie funkcji bibliotecznych:
 * template <class InputIterator, class OutputIterator>
 * OutputIterator copy(InputIterator first, InputIterator last,
 *                      OutputIterator result);
 * oraz
 * template <class InputIterator, class Size, class OutputIterator>
 * OutputIterator copy_n(InputIterator first, Size count, 
 *                      OutputIterator result);
 * 
 * gdzie:
 * 	first - iterator wskazujący na pierwszy element do kopiowania z kontenera
 *	last - iterator na jeden element za ostatnim do kopiowania z kontenera
 *  result - iterator na pierwszy element docelowego kontenera
 *  count - liczba elementów do skopiowania
 * 
 *	Funkcja kopiuje elementy od pierwszego do ostatniego z kontenera pierwszego
 *  wstawiając je od elementu result kontenera docelowego. Używa przypisania
 *  *result = *first, *(result + 1) = *(first + 1) ... 
 *
 *  Funkcja zwraca iterator na pierwszy za ostatnim zmienionm w zbiorze docelowym elementem.
 */

#include <iostream>     // std::cout
#include <algorithm>  	// std::copy
#include <algo.h>  	// std::copy_n
#include <iterator>    	// std::ostream_iterator
#include <vector>       // std::vector
#include <list>         // std::list

using namespace  std;

int main(int argc, char *argv[])
{
    //wektor
    vector<int> v;

    //zapełnianie wektora wartościami 0 - 19      
    for(int i=0; i<20; i++) v.push_back(i);      
    
    //iteratory
    vector<int>::iterator temp, piaty, dziesiaty, pietnasty;        
    temp = v.begin();
    
    for(int i=0; i<5; i++) temp++;
    piaty = temp;

    for(int i=0; i<5; i++) temp++;
    dziesiaty = temp;
    
    for(int i=0; i<5; i++) temp++;
    pietnasty = temp;     
    
    //---------------------------------------------
    
    /* przykład użycia copy - wyświetlanie elementów na standardowe wyjście
     * pierwszy argument to iterator wskazujący na początek obszaru kopiowania
     * drugi argument to iterator wskazujący na koniec obszaru
     * trzeci argument to iterator wskazujący początek obszaru, w który mamy kopiować
     *   w tym wypadku jest to iterator skojarzony ze strumieniem wyjściowym
     */
    copy(v.begin(), v.end(), ostream_iterator<int>(std::cout, " "));    
    cout << endl;
    //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

    /* przykład użycia copy - wyświetlanie elementów na standardowe wyjście
     * pierwszy argument to iterator wskazujący na początek obszaru kopiowania
     * drugi argument to liczba elementów do przekopiwania
     * trzeci argument to iterator wskazujący początek obszaru, w który mamy kopiować
     *   w tym wypadku jest to iterator skojarzony ze strumieniem wyjściowym
     */
    copy_n(v.begin(), v.size(), ostream_iterator<int>(std::cout, " "));    
    cout << endl;
    //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
    
    //---------------------------------------------
    
    /* Zasada działania. Copy i copy_n kopiują elementy z przedziału
     * [first, last) lub [first, first+n) z docelowego  kontenera do
     * elementów [result + (last-first) ) lub [result + n) docelowego kontenera.
     * 
     * Funkcja copy zwraca iterator na pierwszy za elementem z kolekcji docelowej
     * na jakim zakończono kopiowanie.
     */

    //Wektor złożony z 10 zer.
    vector<int> v3(10,0);
    copy(v3.begin(), v3.end(), ostream_iterator<int>(std::cout, " "));
    cout << endl; 
    //0 0 0 0 0 0 0 0 0 0
    
    //Kopiowanie elementów 10-15 z wektora v do el. 0-5 do wektora v3
    // i zapisanie w temp iteratora na pierwszy za ostatnim zmienionym elementem w v3
    temp = copy(dziesiaty, pietnasty, v3.begin());
    
    copy(v3.begin(), v3.end(), ostream_iterator<int>(std::cout, " ")); 
    cout << endl;
    //10 11 12 13 14 0 0 0 0 0
    
    //Kopiowanie 5 elementów od 0 z wektora v do wektora v3 w miejsca od 6
    //temp wskazuje na 6ty element v3
    copy_n(v.begin(), 5, temp);
    
    copy(v3.begin(), v3.end(), ostream_iterator<int>(std::cout, " ")); 
    cout << endl;    
    //10 11 12 13 14 0 1 2 3 4
    
    /* copy i copy_n - wymagania co do argumentow
     */
        
    //---      
    //[first, last) musi być poprawnym przedziałem
    copy(dziesiaty, piaty, ostream_iterator<int>(std::cout, " "));
    cout << endl;
    //funkcja nie zwoci nic, bo first > last
    
    //dla copy_n: n>= 0 oraz {first, first + n) jest poprawnym przedzialem    
    
    //---    
    /* [first, last) nie moze zachodzić na result - 
     * inaczej wynik kopiowania nie bedzie mial sensu
     * bo wartosci zaczna na siebie nachodzic. Taki 
     * problem rozwiazuje copy_backward
     */
    copy(v.begin(), pietnasty, piaty);   
    copy(v.begin(), v.end(), ostream_iterator<int>(std::cout, " ")); 
    cout << endl;        
    //0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
    
    //dla copy_n: analogicznie, result nie nalezy do [first, first + n).
    
    for(int i=0; i<20; i++) v[i] = i; 
    
    /* gdy przedzial oraz result sa poprawne kopiowanie
     * zachodzi zgodnie z zalozeniami
     */
    copy(v.begin(), piaty, dziesiaty);       
    copy(v.begin(), v.end(), ostream_iterator<int>(std::cout, " "));    
    cout << endl;    
    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 15 16 17 18 19
       
    for(int i=0; i<20; i++) v[i] = i;    
       
    //---
    /* liczba elementow skopiowanych powinna miescic sie 
     * w zasiegu poprawnych wartosci (od result do result + N)
     */
    copy(v.begin(), dziesiaty, pietnasty);       
    copy(v.begin(), v.end(), ostream_iterator<int>(std::cout, " "));    
    cout << endl;    
    //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1 2 3 4
    //nie zostalo skopiowane 5 elementow. Skopiowano tylko elementy 0-4
    
    //dla copy_n: analogicznie, [result, result + n) jest poprawnym przedzialem
       
    for(int i=0; i<20; i++) v[i] = i;    
       
    //---------------------------------------------
    // kopiowanie do innych struktur danych    
    list<int> l(v.size());
    copy(v.begin(), v.end(), l.begin());
    //wartosci z wektora v zostały skopiowane do listy l  

    //kopiowaie z listy do wektora
    copy_n(l.begin(), l.size(), v.begin());
    
    copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 
    //---------------------------------------------   
    /* UWAGA
     * copy i copy_n nie tworzą nowych elementów w kontenerze
     * elementy kontenera muszą już istnieć (używany jest operato przypisania)
     */
     
     //wektor pusty
     vector<int> v2(0);
     v2.push_back(100);
     
     copy_n(v.begin(), v.size(), v2.begin());
     copy(v2.begin(), v2.end(), ostream_iterator<int>(std::cout, " "));  
     cout << endl;
     //0
     
    /* Przekopiowano tylko pierwszy element v do v2, ponieważ w wektorze 2
     * było tylko 1 miejsce. Temat był poruszany w części poświęconej argumentom.
     * 
     * Aby wprowadzić nowy element do kontenera, można
     * użyć zamiast iteratora typu outpu_iterator iteratora typu
     * insert iterator, ktory każde przypisanie (operator=) traktuje
     * jak dodanie nowego elementu (v.insert(x)).
     */   
     list<int> l2;
     insert_iterator< list<int> > insert_it(l2, l2.begin());

     copy(v.begin(), dziesiaty, insert_it);
     copy_n(dziesiaty, 5, insert_it);     

     copy_n(l2.begin(), l2.size(), ostream_iterator<int>(cout, " "));
     cout << endl;
     //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
     //Wstawiono 15 elementow do listy z wektora.
}
