// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: testprog.cpp
// Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC
// Produced By: Doug Gaer   
// File Creation Date: 03/25/2000
// Date Last Modified: 08/10/2000
// Copyright (c) 2000 Douglas M. Gaer
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
This library is free software; you can redistribute it and/or 
modify it under the terms of the GNU Lesser General Public 
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. 
  
This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
USA

Test program used to the basic functionality of the Thread Pool
class.
*/
// ----------------------------------------------------------- //   
#include <iostream.h>
#include "thrpool.h"
#include "vthreadt.h"

void PausePrg()
// Pause the program and wait for the user to press enter.
{
  // Pause the program until enter is pressed
  cout << endl;
  cout << "Press Enter to continue...\n";
  cin.get();
}

void ScrollForward(thrPool &pool)
{
  cout << "Walking through the pool..." << endl;
  thrPoolNode *ptr = pool.GetHead();
  while(ptr) {
    cout << (char)ptr->GetThreadPtr()->GetObjectID() << ' ';
    ptr = ptr->GetNext();
  } 
  cout << endl;
}

void RewindPool(thrPool &pool)
{
  cout << "Walking through the pool in a backward direction..." << endl;
  thrPoolNode *ptr = pool.GetTail();

  // Walk through the pool in a backward direction
  while(ptr) {
    cout << (char)ptr->GetThreadPtr()->GetObjectID() << ' ';
    ptr = ptr->GetPrev();
  } 

  cout << endl;
}

int main()
{
  thrPool pool;
  thrPoolNode *ptr;

  cout << "Loading data elements into the pool..." << endl;
  thrPoolNode *na = new thrPoolNode;
  thrPoolNode *nb = new thrPoolNode;
  thrPoolNode *nc = new thrPoolNode;
  thrPoolNode *nd = new thrPoolNode;
  thrPoolNode *n1 = new thrPoolNode;
  thrPoolNode *n2 = new thrPoolNode;
  thrPoolNode *n3 = new thrPoolNode;
  thrPoolNode *n4 = new thrPoolNode;

  // Allocating some memory buffers
  const unsigned num_blocks = 9;
  vbThread_t *buf[num_blocks];
  unsigned i;
  for(i = 0; i < num_blocks; i++) {
    buf[i] = new vbThread_t;
    // Set an arbitary object ID stating starting with ASCII character 'A'
    buf[i]->SetObjectID(65+i);
  }
  
  na->SetThreadPtr(buf[0]);
  nb->SetThreadPtr(buf[1]);
  nc->SetThreadPtr(buf[2]);
  nd->SetThreadPtr(buf[3]);

  // Load some pool elements
  pool.InsertAfter(pool.GetHead(), na);
  pool.InsertAfter(na, nb);
  pool.InsertAfter(nb, nc);
  pool.InsertAfter(nc, nd);
  
  n1->SetThreadPtr(buf[4]);
  n2->SetThreadPtr(buf[5]);
  n3->SetThreadPtr(buf[6]);
  n4->SetThreadPtr(buf[7]);
  
  // Testing insert functions
  pool.InsertBefore(na, n1);
  pool.InsertBefore(nc, n2);
  pool.InsertAfter(nb, n3);
  pool.InsertAfter(nd, n4);

  // Reordering the pool
  pool.MoveToBack(na);
  pool.MoveAfter(na, nc);
  pool.MoveBefore(nc, nb);
  pool.MoveAfter(nc, nd);
  pool.MoveAfter(nd, n2);
  pool.MoveBefore(n2, n1);
  pool.MoveAfter(n2, n3);
  pool.MoveAfter(n3, n4);
  
  ScrollForward(pool);
  RewindPool(pool);

  PausePrg();

  cout << "Adding another item to the pool..." << endl;
  ptr = pool.AddThread(buf[8]);
  ScrollForward(pool);

  PausePrg();

  cout << "Moving pool item to the front of the pool" << endl;
  pool.MoveToFront(ptr);
  ScrollForward(pool);

  cout << "Moving item to the back of the pool..." << endl;
  pool.MoveToBack(ptr);
  ScrollForward(pool);
  
  PausePrg();
  
  cout << "Removing the head of the pool..." << endl;
  ptr = pool.GetHead();
  pool.RemoveNode(ptr);
  ScrollForward(pool);

  cout << "Removing the tail of the pool..." << endl;
  ptr = pool.GetTail();
  pool.RemoveNode(ptr);
  ScrollForward(pool);

  PausePrg();
  cout << "Testing for memory leaks..." << endl;
  unsigned len = sizeof(vbThread_t);
  const unsigned num_to_allocate = 1000; // 1000 * 1000;
  const unsigned mem_bufs = (sizeof(thrPoolNode) + len) * num_to_allocate;
  cout << "Allocating " << mem_bufs << " bytes..." << endl;
  pool.ClearPool();
  unsigned count1 = 0;
  unsigned count2 = 0;
  for(i = 0; i < num_to_allocate; ++i) {
    vbThread_t *sbuf = new vbThread_t;
    count1 += sizeof(sbuf);
    if(!sbuf) {
      cout << "Memory allocation error at " << (count1+count2) << " bytes"
	   << endl;
      break;
    }
    
    count2 += sizeof(thrPoolNode);
    if(!pool.AddThread(sbuf))  {
      cout << "Memory allocation error at " << (count1+count2) << " bytes"
	   << endl;
      break;
    }
  }
  cout << "Done" << endl;
  PausePrg();

  cout << "Releasing memory allocated back to the heap..." << endl;

  while(!pool.IsEmpty()) {
    vbThread_t *t = pool.RemoveTail();
    if(t) delete t;
  }
  pool.MakeEmpty();
  
  PausePrg();
  
  cout << "Exiting..." << endl;
  cout << endl;
  return 0;
}
// ----------------------------------------------------------- // 
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //