Appendix 3: Utilities

Every C++ programmer has files of useful functions that he or she uses in almost every project. Many of the examples in the book include a file called util.h, which is listed in this appendix.

Coding Style Guidelines

util.h follows a simple coding style with only a few basic rules:

1. Names should be chosen to reflect their interpretation. Type names begin with uppercase letters, function, parameter, and variable names begin with lower case letters, and macro names only use uppercase letters.

2. Format should reflect program structure. Indentation levels should reflect nesting levels, blank lines should separate logical tasks, and opening and closing curly braces should be aligned.

3. Comments shouldn't be overdone or underdone. Comments should be literate. Each file begins with a comment that at least contains the file's and author's names. Each function begins with a comment that tells the function's purpose. Non-obvious entry, exit, and exception conditions should also be mentioned. Remarks about algorithm can be included if they're helpful.

Many universities and companies have their own style guidelines, which readers are welcome to use in place of mine, but some style guideline must be followed. There are several proposals for standard C++ style guidelines, which readers may also use.

util.h

/*
* File: pop\util\util.h
* Programmer: Pearce
* Copyright (c): 2000, all rights reserved.
*/

#ifndef UTIL_H
#define UTIL_H

// include just about everything:
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <strstream>
#include <typeinfo>
#include <fstream>
using namespace std;
#include <cmath>
#include <cctype>
#include <cstring>
#include <cerrno>

/*
* Generic error handling for small programs.
*
* EXIT: terminates program if DEBUG_MODE true.
* Throws exception, otherwise.
*/

#define DEBUG_MODE true

inline void error(const string& gripe)
{
   if (DEBUG_MODE)
   {
      cerr << "Error, " << gripe << "!\n";
      exit(1); // terminate program
   }
   else // release mode
      throw runtime_error(gripe);
}

/*
* ostream insertion templates for STL containers
*
* ENTRY: operator<<() must be defined for Data
* EXIT: characters inserted into os
*/

template <typename Data>
ostream& operator<<(ostream& os, const vector<Data>& v)
{
   os << "< ";
   vector<Data>::const_iterator p;
   for( p = v.begin(); p != v.end(); p++)
      os << *p << ' ';
   os << '>';
   return os;
}

template <typename Data>
ostream& operator<<(ostream& os, const list<Data>& v)
{
   os << "( ";
   list<Data>::const_iterator p;
   for( p = v.begin(); p != v.end(); p++)
      os << *p << ' ';
   os << ")";
   return os;
}

template <typename Data>
ostream& operator<<(ostream& os, const set<Data>& v)
{
   os << "{ ";
   set<Data>::const_iterator p;
   for( p = v.begin(); p != v.end(); p++)
      os << *p << ' ';
   os << "}";
   return os;
}

template <typename Key, typename Data>
ostream& operator<<(ostream& os, const pair<Key, Data>& v)
{
   os << '(' << v.first << ", " << v.second << ')';
   return os;
}

template <typename Key, typename Data>
ostream& operator<<(ostream& os, const map<Key, Data>& m)
{
   map<Key, Data>::const_iterator p;
   cout << "{\n";
   for( p = m.begin(); p != m.end(); p++) os << *p << endl;
   cout << "}\n";
   return os;
}

/*
* Searching maps.
*
* ENTRY: k = search key, m = map to
* search, v = a place to store the value
* associated with k in m.
*
* EXIT: Returns true if search was
* successful, and places associated value in v.
* Otherwise, false is returned and v is unchaned.
*/

template <typename Key, typename Data>
bool find(Key k, Data& v, const map<Key, Data>& m)
{
   map<Key, Data>::const_iterator p;
   p = m.find(k);
   if (p == m.end())
      return false;
   else
   {
      v = (*p).second;
      return true;
   }
}

/*
* Binary to string conversion.
*
* ENTRY: operator<<() defined for Data
*/

template <typename Data>
string toString(const Data& val)
{
   ostrstream os;
   os << val << ends;
   return os.str();
}

/*
* String to binary conversion
*
* ENTRY: operator>>() defined for Data
* EXIT: val holds binary value of str
*/

template <typename Data>
void fromString(Data& val, const string& str)
{
   istrstream is(str);
   is >> val;
}

/*
* Generic data entry with error checking.
*
* ENTRY: operator>>() defined for Data
* EXIT: val holds extracted data
*/

template <typename Data>
void getData(Data& var, const string& prompt)
{
   Data response;
   cout << prompt + " -> ";
   while (!(cin >> response))
   {
      cerr << "Invalid entry, ";
      cerr << "please try again or type <Ctrl>c to quit\n";
      cin.clear(); // clear failure flag
      cin.sync(); // flush buffer
      cout << prompt + " -> ";
   }
   cout << "You entered " << response << endl;
   var = response;
}

/*
* Non-blocking way to find out if
* characters are waiting to be read.
*/

inline int moreChars(istream& is = cin)
{
   return is.rdbuf()->in_avail();
}

#endif