
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>

using namespace std;



// Ch 12, Functional Objects - I have a photocopy of several
// chapters, but can't find the author, or book title.
// This was my first book on STL, and its a beauty.  My
// former boss Clouse picked it up in Sinapore

void initvec(vector<int>& v)
{
   int test[] = {4,6,8,10,12};
   const int testN = sizeof(test)/sizeof(int);

   vector<int> v2(test,test+testN);
   v=v2; 
}


// Initializing a vector array, ouputing with an output iterator and copy
void test01()
{
   vector<int> v;
   initvec(v);

   ostream_iterator<int> output(cout," ");
   copy(v.begin(),v.end(),output);
}


// Data Encapulation
//
// What is really interesting is how the data is encapulated.
// By binding the result to a variable, the data destination
// is secured, and is only public in the constructor.
//


template<class T>
class smsquare
{
   T& counter;
public:

   smsquare(T& counter_) : counter(counter_) { counter=0; }

   T operator()(T x) { T t=x*x; counter += t; return t; }
};

//
// Investigate transform, which is really a mapping
//
void test02()
{
   vector<int> v;
   initvec(v);

   ostream_iterator<int> output(cout," ");
   copy(v.begin(),v.end(),output);
   cout << endl << endl;

   vector<int> v2(5);
   int count; 
   transform(v.begin(),v.end(), v2.begin(), smsquare<int>(count));

   copy(v2.begin(),v2.end(),output);
   // if didn't resize v2, use back_inserter

   cout << "count=" << count << endl << endl;

   cout << "Using for_each instead of transform" << endl;
   int count2;
   // applies a unary mapping function
   for_each(v.begin(),v.end(),smsquare<int>(count2));
   cout << "count2=" << count2 << endl << endl;
}

//
// Using STL generic algorithms to do the same job
// At first sight I didn't like STL.  But things change,
// and these are general/powerful algorithms, with minimal code
//
void test03()
{
   vector<int> v;
   initvec(v);

   vector<int> v2(v.size());

   // Transform using a binary function
   transform(v.begin(),v.end(),v.begin(),v2.begin(), multiplies<int>());

   copy(v2.begin(),v2.end(),ostream_iterator<int>(cout," "));
   cout << endl;

   // #include <numeric>
   int sum = accumulate(v2.begin(),v2.end(),0,plus<int>());
   cout << "sum = " << sum << endl;
}

// multiply the container elements by 10
// Use of bind1st and bind2nd - great
void test04()
{
   vector<int> v;
   initvec(v);
   vector<int> v2(v.size());

   transform(v.begin(),v.end(),v2.begin(), bind2nd(multiplies<int>(),10));

   copy(v2.begin(),v2.end(),ostream_iterator<int>(cout," "));
   cout << endl << endl;

   transform(v2.begin(),v2.end(),v.begin(),bind1st(plus<int>(),3) );
   copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
   cout << endl;
}
  

void test05()
{
   vector<int> v;
   initvec(v);
   vector<int> v2;

   // <TODO> compoisition
   transform( v.begin(),v.end(),back_inserter(v2),bind1st(plus<int>(),3) );
  
   copy(v2.begin(),v2.end(),ostream_iterator<int>(cout," "));
   cout << endl << endl;

}

// binary function x*x+y*y

//
// Writing a binary function by deriving from binary_function
//


// calculate a distance and direction
template<class X>
struct distance1 : public binary_function<X,X,pair<X,int> >
{
   pair<X,int> operator () (X x, X y)
   {
      X d = x*x + y*y;

      // assign a quadrant to point
      int quad;
      if (x<0)
      {
         (y<0) ? quad=2 : quad=1;
      }
      else
      {
         (y<0) ? quad=3 : quad=0;
      }
     
      return make_pair(d,quad);
   }
};

#include "misc.h"

void test06()
{
   
   distance1<double> d;

   pair<double,int> p1 = d(.2,.7);
   pair<double,int> p2 = d(-4,3);

   cout << p1 << endl;
   cout << p2 << endl;
}


#include <stack>
// testing stack, container adapter
void test07()
{
   // deque is the default container
   stack<double> s1;

   cout << "pushed 1.2, 5.3, 11.9 onto the stack" << endl << endl;
   s1.push(1.2);
   s1.push(5.3);
   s1.push(11.9);

   cout << SHOW( s1.empty() ) << endl;
   cout << SHOW( s1.top() ) << endl;
   cout << SHOW( s1.size() ) << endl;

   stack<double> s2(s1);
   cout << SHOW( s1.top() ) << endl;

   // can copy the stack to another stack
   stack<double> s3;
   s3=s2;
   s3.pop();
   cout << SHOW( s3.top() ) << endl;

   // Can't get the container back out eg no easy conversion
   // between stack and other containers, could derive
   // from stack with say a copy function that copies
   // the protected container c out 

   // Initializing the stack, with the same type of container
   // the stack is using

   int a[5] = { 32, -3, 903, 23, 4 }; 
   deque<int> da(a,a+5);
   stack<int> s4(da);
   cout << SHOW( s4.top() ) << endl;

   vector<int> va(a,a+5);
   stack<int,vector<int> > s5(va);
   cout << SHOW( s5.top() ) << endl;
}

      




int main()
{
   test07();

   return 0;
}

