/**************************************************************************\

MODULE: tools

SUMMARY:

Some useful tools that are used throughout NTL.

\**************************************************************************/

#include <cstdlib>
#include <cmath>
#include <cstring>

#include <utility>
#include <iostream>
#include <new>
#include <stdexcept>

#include <NTL/config.h>
#include <NTL/mach_desc.h>




double GetTime();
// returns number of seconds of CPU time used by this process.

double GetWallTime();
// returns the "wall clock" time, measured since the beginning
// of some unspecified epoch.  This is useful for measuring the
// performance of multi-threaded code, since in this case,
// GetTime does not return very useful information in that case.

void PrintTime(ostream& s, double t);
// prints the time t (in seconds) to s in the format
//     ss  or  mm:ss  or  hh:mm:ss,
// where the value t is first rounded to the nearest integer.


long IsWhiteSpace(long c);
// returns 1 if c is "white space" (as defined by isspace is the
// standard library...usually blanks, tabs, newlines), and 0 otherwise.

long SkipWhiteSpace(istream& s);
// skips white space (as defined by IsWhiteSpace).
// Return value is 0 if end-of-file is reached; otherwise,
// return value is 1.


long IsEOFChar(long c);
// test if c == EOF


long CharToIntVal(long c);
// returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f';
// otherwise, the return value is -1.

char IntValToChar(long x);
// returns the hexadecimal digit '0'..'9', 'a'..'f' representing x;
// an error is raised if x < 0 or x > 15.

long IsFinite(double *p);
// Returns 1 if *p is a "finite" floating point number.
// A pointer is used to ensure that the number is in memory,
// which on some architectures (notably x86/Pentium) can make a difference.

// some min/max and swap routines:

int min(int a, int b);
int max(int a, int b);

long min(long a, long b);
long max(long a, long b);

long min(int a, long b);
long max(int a, long b);

long min(long a, int b);
long max(long a, int b);

unsigned int min(unsigned int a, unsigned int b);
unsigned int max(unsigned int a, unsigned int b);

unsigned long min(unsigned long a, unsigned long b);
unsigned long max(unsigned long a, unsigned long b);

unsigned long min(unsigned int a, unsigned long b);
unsigned long max(unsigned int a, unsigned long b);

unsigned long min(unsigned long a, unsigned int b);
unsigned long max(unsigned long a, unsigned int b);


void swap(long& a, long& b);
void swap(int& a, int& b);


// defined here are all the conversion routines among the types 
// int, long, float, double.  See conversions.txt for complete details.



// The following platform-dependent macros are defined:

#define NTL_BITS_PER_LONG      (...)  /* bits in a long */
#define NTL_MAX_LONG           (...)  /* max value of a long */
#define NTL_MIN_LONG           (...)  /* min value of a long */

#define NTL_BITS_PER_INT       (...)  /* bits in a int */
#define NTL_MAX_INT            (...)  /* max value of a int */
#define NTL_MIN_INT            (...)  /* min value of a int */

#define NTL_DOUBLE_PRECISION   (...)  /* # of bits of precision in a double */
#define NTL_FDOUBLE_PRECISION  (...)  /* the double value 
                                        2^{NTL_DOUBLE_PRECISION-1} */

#define NTL_ARITH_RIGHT_SHIFT  (...)  /* 1 if signed right-shift is
                                        arithmetic; 0 otherwise */

#define NTL_EXT_DOUBLE         (...)  /* 1 if platform has "extended" doubles;
                                        0 otherwise */


// ERROR HANDLING

void TerminalError(const char *s);
// print an error message and call abort

extern thread_local void (*ErrorMsgCallback)(const char *);
extern thread_local void (*ErrorCallback)();
// Pointers (initially NULL) to callback functions.
// Upon encountering an unrecoverable error with an error
// message s, the following happens:
//
//    if (ErrorMsgCallback)
//       (*ErrorMsgCallback)(s);
//    else
//       cerr << s << "\n";
// 
//    if (ErrorCallback) (*ErrorCallback)();
//    abort();
//
// NOTE: if threads are enabled, these are actually thread_local variables.



// The following classes are defined even if exceptions are not
// enabled with NTL_EXCEPTIONS

class ErrorObject : public runtime_error {
public:
   ErrorObject(const char *msg);
};

class LogicErrorObject : public ErrorObject {
public:
   LogicErrorObject(const char *msg);
};

class ArithmeticErrorObject : public ErrorObject {
public:
   ArithmeticErrorObject(const char *msg);
};

class ResourceErrorObject : public ErrorObject {
public:
   ResourceErrorObject(const char *msg);
};

class FileErrorObject : public ErrorObject {
public:
   FileErrorObject(const char *msg);
};

class InputErrorObject : public ErrorObject {
public:
   InputErrorObject(const char *msg);
};


// The following functions throw the indicated exception if
// exceptions are enabled with NTL_EXCEPTIONS; otherwise,
// they simply invoke TerminalError.

void MemoryError();
// throws bad_alloc

void Error(const char *msg);
// throws ErrorObject

void LogicError(const char *msg);
// throws LogicErrorObject

void ArithmeticError(const char *msg);
// throws ArithmeticErrorObject

void ResourceError(const char *msg);
// throws ResourceErrorObject

void FileError(const char *msg);
// throws FileErrorObject

void InputError(const char *msg);
// throws InputErrorObject