// Lösungen zu "Richard Kaiser: C++ mit dem Borland C++Builder 2007", ISBN: 978-3-540-69575-2
// Copyright Richard Kaiser, 2007. http://www.rkaiser.de. All rights reserved.
// Diese Quelltexte dürfen in eigenen Programmen verwendet werden, wenn sie einen Hinweis auf die Quelle (die ersten beiden Zeilen) enthalten. In keinem Fall wird eine Haftung für direkte, indirekte, zufällige oder Folgeschäden übernommen, die sich aus der Nutzung ergeben.
// It is permitted to use this source text in programs of your own, provided that it contains a reference to the source (the first two lines above). All liabilities for use of the code are disclaimed.

#include <vcl.h>
#pragma hdrstop
#include "IteratU.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}


// --------------- Aufgaben 9.4 ----------------------------

// --------------- Aufgabe 1 -------------------------------

#include <fstream>
#include <algorithm>
using namespace std;

// a)
template<typename T,typename Iterator>
void writeToFile(Iterator first, Iterator last, char* fn)
{
ofstream f(fn);
copy(first, last, ostream_iterator<T>(f,"\n"));
}

// b)
template<typename T> void copyFile(char* fn1,char* fn2)
{
ifstream f1(fn1);
ofstream f2(fn2);
copy(istream_iterator<T>(f1),
     istream_iterator<T>(),ostream_iterator<T>(f2,"\n"));
}

// c)

#include <iterator>
#include <vector>

template<typename T> void sortFile(char* fn1,char* fn2)
{
ifstream f1(fn1);
vector<T> v;
copy(istream_iterator<T>(f1),
     istream_iterator<T>(),back_inserter(v));
sort(v.begin(),v.end());
ofstream f2(fn2);
copy(v.begin(), v.end(), ostream_iterator<T>(f2,"\n"));
}

// d)

#include <functional> 

template<typename T, typename Iterator>
bool is_sorted(Iterator first, Iterator last)
{
return adjacent_find(first,last,greater<T>())==last;
}

template<typename T>
bool FileIsSorted(char* fn)
{
ifstream f(fn);
return is_sorted<T>(istream_iterator<T>(f),istream_iterator<T>());
}

// e)

template<typename T> void print(T x)
{
Form1->Memo1->Lines->Add(x);
}

template<typename T> void showFile(char* fn)
{
print<char*>(fn);
ifstream f(fn);
for_each(istream_iterator<T>(f),istream_iterator<T>(),print<T>);
}

// g)
struct Bruch {
  Bruch():z(0),n(1) {}
  Bruch(int z_,int n_):z(z_),n(n_) {}
  int z,n; // z: Zähler, n: Nenner
};

ostream& operator<<(ostream& f, const Bruch& b)
{
return f<<b.z<<"|"<<b.n;
}

istream& operator>>(istream& f, Bruch& b)
{
char Bruchstrich;
f>>b.z>>Bruchstrich>>b.n;
return f;
}


void Aufg1()
{
// f)
int as[3]={1,2,3};                         // sortiert
writeToFile<int>(as,as+3,"s.txt");
int au[3]={1,3,2};                         // unsortiert
writeToFile<int>(au,au+3,"u.txt");
int a0[1];
writeToFile<int>(a0,a0,"0.txt");   // 0 Elemente
int a1[1]={1};
writeToFile<int>(a1,a1+1,"1.txt"); // 1 Element

bool b1=FileIsSorted<int>("s.txt");
bool b2=FileIsSorted<int>("u.txt");
bool b3=FileIsSorted<int>("0.txt");
bool b4=FileIsSorted<int>("1.txt");

copyFile<int>("s.txt", "sc.txt");
copyFile<int>("u.txt", "uc.txt");
copyFile<int>("0.txt", "0c.txt");
copyFile<int>("1.txt", "1c.txt");

sortFile<int>("s.txt", "ss.txt");
sortFile<int>("u.txt", "us.txt");
sortFile<int>("0.txt", "0s.txt");
sortFile<int>("1.txt", "1s.txt");

bool b1s=FileIsSorted<int>("ss.txt");
bool b2s=FileIsSorted<int>("us.txt");
bool b3s=FileIsSorted<int>("0s.txt");
bool b4s=FileIsSorted<int>("1s.txt");

showFile<int>("s.txt");
showFile<int>("u.txt");
showFile<int>("0.txt");
showFile<int>("1.txt");

showFile<int>("ss.txt");
showFile<int>("us.txt");
showFile<int>("0s.txt");
showFile<int>("1s.txt");

// g)
vector<Bruch> vb;
vb.push_back(Bruch(1,2));
vb.push_back(Bruch(1,3));
vb.push_back(Bruch(1,4));
writeToFile<Bruch>(vb.begin(),vb.end(),"b.txt");
}

void __fastcall TForm1::Button_4_1Click(TObject *Sender)
{
Aufg1();
}


// --------------- Aufgabe 2 -------------------------------

/* Zur Lösung dieser Aufgabe müssen der Klasse Array
   lediglich diese Definitonen hinzugefügt werden:

    typedef T*             iterator;
    iterator begin() { return elems; }
    iterator end() { return elems+N; }
*/

#include <stdexcept> // für range_error
#include <sstream>   // für Exception Text

template<class T, unsigned int N>
class Array {
  public:
    T elems[N];    // fixed-size array of elements of type T

    // kein Konstruktor, damit ein Array wie ein C-Array
    // initialisiert werden kann
  public:
    // type definitions
    typedef T              value_type;
    typedef T&             reference;
    typedef const T&       const_reference;
    typedef std::size_t    size_type;

    // operator[]
    reference operator[](unsigned int i)
    {
    if (i>=N) // bzw. (i<0 || i>=N) bei int i;
      {
        std::ostringstream msg;
        msg<<"Array index out of range: "<<i<<" > "<<(N-1);
        throw std::out_of_range(msg.str());
      }
    return elems[i];
    }

    // ohne diese Variante ist der Indexoperator für konstante
    // Arrays wie
    //    const Array<int, n> a={1,2,3};
    // nicht definiert:
    const_reference operator[](unsigned int i) const
    {
    if (i>=N) // bzw. (i<0 || i>=N) bei int i;
      {
        std::ostringstream msg;
        msg<<"Array index out of range: "<<i<<" > "<<(N-1);
        throw std::out_of_range(msg.str());
      }
    return elems[i];
    }

    // size is constant
    static size_type size() { return N; }

    // Ergänzungen:

    typedef T*             iterator;
    iterator begin() { return elems; }
    iterator end() { return elems+N; }

    // Die nächsten drei Definitionen ermöglichen den Aufruf
    // von STL-Algorithmen mit konstanten Array.
    typedef const T*       const_iterator;
    const_iterator begin() const { return elems; }
    const_iterator end() const { return elems+N; }
};

#include <algorithm>
void test_Array()
{
Array<int,5> a={1,9,-1, 6,2};
std::sort(a.begin(),a.end());


}


void __fastcall TForm1::Button_4_2Click(TObject *Sender)
{
test_Array();
}


// --------------- Aufgabe 3 -------------------------------

template<> void print(Bruch x)
{
Form1->Memo1->Lines->Add(AnsiString(x.z)+"|"+AnsiString(x.n));
}

void Aufg3()
{
ifstream f("s.txt");
istream_iterator<int> beg1(f);
istream_iterator<int> end1;
vector<int> v1(beg1,end1);
for_each(v1.begin(),v1.end(),print<int>);

ifstream fb("b.txt");
istream_iterator<Bruch> beg2(fb);
istream_iterator<Bruch> end2;
vector<Bruch> vb(beg2,end2);
for_each(vb.begin(),vb.end(),print<Bruch>);
}

void __fastcall TForm1::Button_4_3Click(TObject *Sender)
{
Aufg3();
}




