// 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.

/*
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

// Copyright notice for the array example:

/ * The following code declares class array,
 * an STL container (as wrapper) for arrays of constant size.
 *
 * See
 *      http://www.boost.org/libs/array/
 * for documentation.
 *
 * The original author site is at: http://www.josuttis.com/
 *
 * (C) Copyright Nicolai M. Josuttis 2001.
 *
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * /

// Copyright notice for the scoped_ptr example:

//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
//  Copyright (c) 2001, 2002 Peter Dimov
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
//  http://www.boost.org/libs/smart_ptr/scoped_ptr.htm
//


*/


//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "ClassTemplU.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------


__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
// Erzeuge das Verzeichnis, falls es nicht existiert
AnsiString dir="c:\\test";
if (CreateDirectory(dir.c_str(),0))
  ShowMessage("directory '"+dir+"' created");
}


// --------------- Aufgaben 9.2 ----------------------------


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

// In der Boost-Bibliothek (http://boost.org, boost\array.hpp)
// ist das fixed size array "array" im Wesentlichen
// folgendermaßen definiert (stark vereinfacht):

#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; }

};


void test_Array()
{
const int n=100;
Array<int, n> a;
for (int i=0;i<n;i++) a[i]=i;
int s=0;
for (int i=0;i<n;i++) s=s+a[i];
Form1->Memo1->Lines->Add("s="+IntToStr(s));
int x=a.size();
// Da Array keine Konstruktoren hat, kann es wie ein C-Array
// initialisiert werden:
Array<int, n> ai={1,2,3};

const Array<int, n> c={1,2,3};
for (int i=0;i<n;i++) s=s+c[i];
Form1->Memo1->Lines->Add("s="+IntToStr(s));

try {
      a[n]=0; // löst eine Exception aus
    }
catch (std::exception& e)
    {
      Form1->Memo1->Lines->Add(e.what());
    }
try {
      a[-1]=0; // löst eine Exception aus
    }
catch (std::exception& e)
    {
      Form1->Memo1->Lines->Add(e.what());
    }
}

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


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

// In der C++-Standardbibliothek ist das Funktions-Template make_pair
// in <utility> folgendermaßen definiert:

using std::pair;

template <class T1, class T2>
pair<T1, T2> makePair(const T1& x, const T2& y)
{
return pair<T1, T2>(x, y);
}

#include <map>

void test_makePair()
{
using std::map;
using std::string;

map<string,string> ac;
#if __BORLANDC__ >= 0x590 // C++Builder 2007
ac.insert(makePair(string("Daniel"),string("13.10.89")));
#else
ac.insert(makePair("Daniel","13.10.89"));
#endif
if (ac.find("Daniel")!=ac.end())
  {
    Form1->Memo1->Lines->Add("makePair funktioniert");
    string result=ac["Daniel"];
  }
else
  Form1->Memo1->Lines->Add("makePair funktioniert nicht");
}

void __fastcall TForm1::Button_2_2Click(TObject *Sender)
{
test_makePair();
}






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

template <typename T>
struct Punkt1 {
  T x,y;
  Punkt1(const T& a,const T& b):x(a),y(b) {}
  Punkt1(const Punkt1& p):x(p.x),y(p.y){ };
};

template <typename T>
struct Punkt2 {
  T x,y;
  Punkt2(const T& a,const T& b):x(a),y(b) {}
  template <typename U>
  Punkt2(const Punkt2<U>& p):x(p.x),y(p.y){ };
};

void Aufg3()
{
Punkt1<int> p1a(1,2);        Punkt2<int> p2a(1,2);
Punkt1<int> p1b=p1a;         Punkt2<int> p2b=p2a;
// Punkt1<double> p1c=p1a; // ohne den zweiten Konstruktor nicht möglich
Punkt2<double> p3b=p2a;
}

void __fastcall TForm1::Button_2_3Click(TObject *Sender)
{
//
}

// --------------- Aufgabe 4 -------------------------------

// In der Boost-Bibliothek (http://boost.org, boost\scoped_ptr.hpp)
// ist das Klassen-Template scoped_ptr im Wesentlichen
// folgendermaßen definiert (stark vereinfacht).
// Dieses Template entspricht der Klasse MyVerySimpleSmartPointer.

template<class T> class scoped_ptr
{
  private:
    T * ptr;

    scoped_ptr(scoped_ptr const &);
    scoped_ptr & operator=(scoped_ptr const &);
  public:
    explicit scoped_ptr(T * p = 0): ptr(p) {} // never throws

    ~scoped_ptr() // never throws
    {
      delete ptr;
    }

    T & operator*() const // never throws
    {
        return *ptr;
    }

    T * operator->() const // never throws
    {
        return ptr;
    }
};

void testMyScopedPtr()
{
scoped_ptr<int> sp1(new int);
*sp1=17;
int* p2=new int(18);
scoped_ptr<int> sp2(p2);
// sp1=sp2; // nicht möglich
}


void __fastcall TForm1::Button_2_4Click(TObject *Sender)
{
testMyScopedPtr();
}

// --------------- Aufgabe 5 -------------------------------

template<class T>
T Average(const T* data, int numElements)
{
   T sum = 0;
   for (int i=0; i < numElements; ++i)
       sum += data[i];
   return sum / numElements;
};

double Average(const int* data, int numElements)
{
   double sum = 0;
   for (int i=0; i < numElements; ++i)
       sum += data[i];
   return sum / numElements;
};


template<class T> struct float_trait {
   typedef T      T_float;
};

template<> struct float_trait<int> {
   typedef double T_float;
};

template<> struct float_trait<char> {
   typedef double T_float;
};

template<class T>
typename float_trait<T>::T_float average(const T* data,
   int numElements)
{
   typename float_trait<T>::T_float sum = 0;
   for (int i=0; i < numElements; ++i)
       sum += data[i];
   return sum / numElements;
}

/*
Die float_trait-Variante ist nicht so leicht verständlich,
erspart aber doppelten Code (insbesondere, falls noch weitere
Varianten notwendig sind).
*/

void testAverage()
{
const int Max=2;
int d1[Max]={1,2};
double a1=Average(d1,Max);
double d2[Max]={1,2};
double a2=Average(d2,Max);

double a10=average(d1,Max);
double a21=average(d2,Max);

}

void __fastcall TForm1::Button_2_5Click(TObject *Sender)
{
testAverage();
}


//----- Aufgabe 6 ----------------------------------------------------------

template<class charT> struct IntDouble_traits;
template<> struct IntDouble_traits<int>{};
template<> struct IntDouble_traits<double>{};

template <typename T, typename traits=IntDouble_traits<T> >
class NurIntDouble {
  traits t;

  T x;
};

void test_NurIntDouble()
{
NurIntDouble<int> x;
NurIntDouble<double> d;
// NurIntDouble<char> c; // das geht nicht
}

void __fastcall TForm1::Button_2_6Click(TObject *Sender)
{
test_NurIntDouble();
}


// --------------- Aufgabe 7 -------------------------------

#include "..\..\CPPUtils\BinStream.h"

void test_binary_stream()
{
binary_fstream<int> f("c:\\test\\bin",ios::out);
if (f)
 {
    for (int i=0; i<10; i++)
      if (!f.write_bin(i))
        ShowMessage("Fehler write f");
    f.close();
  }
else
  ShowMessage("Fehler open bin");
f.clear();

f.open("c:\\test\\bin");
if (f)
 {
    int x;
    while (f.read_bin(x))
      {
      Form1->Memo1->Lines->Add(IntToStr(x));
      }
    f.close();
  }
else
  ShowMessage("Fehler open bin");

binary_ifstream<int> fin("c:\\test\\bin1");
if (fin)
 {
    int x;
    while (fin.read_bin(x))
      {
      Form1->Memo1->Lines->Add(IntToStr(x));
      }
    fin.close();
  }
else
  ShowMessage("Fehler open bin1");

binary_ofstream<int> fout("c:\\test\\bin1");
if (fout)
 {
    for (int i=0; i<10; i++)
      if (!fout.write_bin(i))
        ShowMessage("Fehler write fout");
    fout.close();
  }
else
  ShowMessage("Fehler open bin1");
}

void __fastcall TForm1::Button_2_7Click(TObject *Sender)
{
test_binary_stream();
}


//----- Aufgabe 8 ----------------------------------------------------------

template<class T> class myAutoPtr
{ // stark vereinfachte Version der Klasse auto_ptr
  T* ptr;
 public:
  myAutoPtr (T* p)  throw() : ptr(p) { }

  myAutoPtr(myAutoPtr<T>& a)  throw() // Copy-Konstruktor
  {
  T* tmp=a.ptr;
  a.ptr=0;
  ptr=tmp;
  }

  myAutoPtr<T>& operator= (myAutoPtr<T>& rhs)  throw() // operator=
  {
  if (ptr != rhs.ptr)
    {
      T* tmp = rhs.ptr;
      rhs.ptr = 0;
      delete ptr;
      ptr = tmp;
    }
  return *this;
  }

  ~myAutoPtr() throw() { delete ptr; }

// members
  T& operator*  ()  const throw() { return *ptr;   }
  T* operator-> ()  const throw() { return ptr;    }
  T* get        ()  const throw() { return ptr;    }
};


void test_myAutoPtr_1()
{
int* p=new int(1);
myAutoPtr<int>ap1(p);
myAutoPtr<int>ap2(p);
int* pa=new int[10];
myAutoPtr<int>ap3(pa); // zulässig, aber falsch
int i;
myAutoPtr<int>ap4(&i); // zulässig, aber falsch
myAutoPtr<int> ap(new int(1)); // ap.ptr=x mit x>0
myAutoPtr<int> aq(new int);  // aq.ptr=0
aq=ap; // aq.ptr=x, ap.ptr=0
}


class C {
 public:
  C(){
  Form1->Memo1->Lines->Add("Konstruktor ");
  }

  ~C(){
  Form1->Memo1->Lines->Add("Destruktor");
  }

};

void test_myAutoPtr_2()
{
C* pc1=new C;
C* pc2=new C;

myAutoPtr<C> p(pc1);
myAutoPtr<C> q(pc2);
p=q;
myAutoPtr<C> r(p);

C* pc;
//p=pc;
}

void __fastcall TForm1::Button_2_8Click(TObject *Sender)
{
test_myAutoPtr_1();
test_myAutoPtr_2();
}



