Code - common functions
About
When making large programs, you'll probably notice there are a few basic functions for number, string and vector manipulation which you call again an again. Common function like this might include:
- finding the average of two numbers .............................. (a "basic function")
- getting the area of a circle .......................................... (a "geometry function")
- converting a number (or anything else) to a string ........ (a "string function")
- replacing certain words in a string with other words ..... (a "string function")
- generating a random number between two values ........ (a "random number function")
- getting the current time as a string .............................. (a "time function")
- eliminating any duplicates in a vector ........................... (a "vector function")
- saving a string to a file ................................................. (a "file function")
- ... and any number of other little functions.
The solution I like to use is to create a file called "_common_functions.cpp" where I write all these common functions as (fast) inline methods, so that I can #include this file (#include "_common_function.h") in the top of any other files which may need these methods. No matter what language I used (C++, JavaScript, Java, C#, PHP, etc) I'll tend to create a "common functions" file and over time the number of methods I rely on seems to get longer and longer. Rather than paste all the different language, I've decided to include here just the C++ version.
Disclaimer:
- Several few of these functions, such as "MIN" and "MAX" and "swapVals", plus some of the constants, already live in the <algorithms> and <limits.h> libraries in C++, however I've still included them here for completeness as they may not live in other languages. Hope some of these functions are of help!
- Most of these functions were written years ago, and I haven't checked over them all lately to see if they all work... or to improve their efficiency.
Common Functions
Below are the contents of "_common_function.h"
//----------------------------------------------------------------------------
// _common_functions.h -- Contains several inline functions and templated
// functions which I commonly use.
//
// NOTE: inline template functions have been used instead of macros
// because, although macros produce simple code
// (e.g.: "#define SQ(x) ((x)*(x))"), macros are generally less efficient
// and not recommended in c++ programming.
//
// > author: Andrew Noske
// > last updated: 4-June-2012
//
// http://www.andrewnoske.com/wiki/index.php?title=Code_-_common_functions
//----------------------------------------------------------------------------
#ifndef INC_COMMON_FUNCTIONS_H
#define INC_COMMON_FUNCTIONS_H
//############################################################
//## INCLUDES:
#include <math.h> // For some simple maths algorithms.
#include <limits.h> // For INT_MAX.
#include <stdio.h> // For file I/O.
#include <vector> // For use of vectors.
#include <sstream> // For formatting string output.
#include <iostream> // For redirecting cout.
#include <string> // For string.
#include <algorithm> // For special algorithms (such as sort() and tranform()).
using namespace std;
//############################################################
//----------------------------------------------------------------------------
//
// CONSTANTS:
//
//----------------------------------------------------------------------------
//## GEOMETRY RELATED:
enum angletype { X, Y, Z, ALL, NONE };
const double PI = 3.141592654;
const double RADS_TO_DEGS = 180.0/PI;
const double DEGS_TO_RADS = PI/180.0;
//## LIMITS:
const long MAX_LONG = (long)2147483647; // Largest negative value of a long.
const long MIN_LONG = (long)2147483648; // Largest positive value of a long.
const int MAX_INT = (int)32767; // Largest negative value of a (singed) int.
const int MIN_INT = (int)32768; // Largest positive value of a (signed) int.
const double DOUBL_MAX = (double) 1.7976931348623158e+308; // Largest pos double.
const double DOUBL_MIN = (double)-1.7976931348623158e+308; // Largest neg double.
const float FLOAT_MAX = (float) 3.40282e38; // Largest positive value float.
const float FLOAT_MIN_POS = (float) 1.17549e-38; // Smallest positive value float.
const float FLOAT_MIN = (float)-3.4027e35; // Largest negative value float.
//----------------------------------------------------------------------------
//
// FUNCTION DECLARATION:
//
//----------------------------------------------------------------------------
//## BASIC FUNCTIONS:
template <typename type> type SQ(type x);
template <typename type> type CUBE(type x);
template <typename type> type MIN(type val1, type val2);
template <typename type> type MAX(type val1, type val2);
template <typename type> void updateMax(type &max, type newVal);
template <typename type> void updateMin(type &min, type newVal);
template <typename type> type ABS(type val);
template <typename type> void swapVals(type &val1, type &val2);
template <typename type> void swapValsAsc(type &val1, type &val2);
template <typename type> void keepWithinRange(type &val, type min, type max);
template <typename type> bool isBetween(type limit1, type val, type limit2);
template <typename type> bool isBetweenAsc(type min, type middle, type max);
template <typename type> bool isBetweenNI(type limit1, type val, type limit2);
inline float fMod(float val, float modVal);
inline int intMod(int val, int modVal);
inline float fModWithinRange(float val, float min, float max);
inline void changeIntWithinRange(int &val, int min, int max, int increment);
inline void cycleIntWithinRange(int &val, int min, int max, int increment);
template <typename type> void changeNumWithinRange(type &val, type min, type max, type changeAmount);
inline float fDiv(float numerator, float denominator);
inline float fDivCustom(float numerator, float denominator, float infinityValue=FLOAT_MAX);
inline bool isFactor(float value, float divisor);
inline int roundToInt(float x);
inline float roundPrec(float value, float precision);
inline float roundDecimal(float value, int decimal);
inline float avg(float val1, float val2);
inline float getFractBetween(float val1, float val2, float fractTowards2);
inline float calcPercent(float numerator, float denominator);
inline int calcPercentInt(float numerator, float denominator);
inline int calcPercentFloor(float numerator, float denominator);
//## GEOMETRY FUNCTIONS:
inline void keepAngleInRange(float &angle);
inline float geom_volumeSphere(const float radius);
inline float geom_surfaceAreaSphere(const float radius);
inline float geom_volumeConicalFrustrum(const float rBase, const float rTop, const float height);
inline float geom_surfaceAreaConicalFrustrum(const float rBase, const float rTop, const float height);
inline float geom_areaCircle(const float radius);
//## STRING FUNCTIONS:
template <typename type> string toString(type value);
template <typename data> string toStringPadNumber(data value, int padLength, char padChar='0');
template <typename data> string toStringWithCommas(data value);
inline string toString(float value, int decimal);
inline float string_getFloatFromString(string str);
inline string string_substr (string str, int chars, int offset);
inline string string_substrFromEnd (string str, int charsAtEnd);
inline bool string_startsWith (const string haystack, const string needle);
inline string string_replace (string str, const string searchStr, const string replaceStr);
inline string string_eliminateDuplicates(const string haystack, const string needle);
inline vector<string> string_explode(string str, string explodeStr);
inline string string_explodeGetArgument(string str, string sepStr, int argNum, bool eliminateDuplicates=true);
//## RANDOM NUMBER FUNCTIONS:
inline void seedRandom();
inline double highResRand();
inline double randCoef();
inline double randCoefOneNotInclusive();
inline double randHighResCoef();
inline double randHighResCoefOneNotInclusive();
inline double randDbl(double min, double max);
inline int randIntInclusive(int min, int max);
inline float randFlt(float min, float max);
//## TIME FUNCTIONS:
inline string time_getCurrTimeStampString();
inline string time_getCurrTimeStampStringWithUnderscores();
inline long time_getCurrTimeInSecs();
inline string time_formatTimeElapsed(long secsElapsed, bool includeSecs, bool simpleFormat);
//## VECTOR FUNCTIONS:
template <typename type> bool vector2D_transpose(vector< vector<type> > &v);
template <typename type> void vector_eliminateDuplicates(vector<type> &v);
template <typename type> bool vector_doesElementExistInVector(vector<type> v, type element);
template <typename type> vector<type> vector_concat(vector<type> &v1, vector<type> &v2);
template <typename type> vector<type> vector_sort(vector<type> v, int startIdx, int endIdx=INT_MAX);
template <typename type> vector<type> vector_sort(vector<type> v);
template <typename type> vector<type> vector_reverse(vector<type> v, int startIdx=0, int endIdx=INT_MAX);
//## FILE FUNCTIONS:
inline bool file_saveStringToFile(string filePath, string text, bool append);
inline vector<string> file_loadTextFromFile(string filePath, bool printStatus=true);
//----------------------------------------------------------------------------
//
// FUNCTION DEFINITIONS:
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//## BASIC FUNCTIONS
//----------------------------------------------------------------------------
//----------------
//-- Returns the given number squared
template <typename type>
inline type SQ(type x) { return (x*x); }
//----------------
//-- Returns the given number cubed
template <typename type>
inline type CUBE(type x) { return (x*x*x); }
//----------------
//-- Returns the smaller of the two values fed in (NOTE: this
//-- function already exists, but use capitals to avoid ambiguity)
template <typename type>
inline type MIN(type val1, type val2)
{ return (val1 < val2) ? val1 : val2; }
//----------------
//-- Returns the greater of the two values fed in (NOTE: this
//-- function already exists, but use capitals to avoid ambiguity)
template <typename type>
inline type MAX(type val1, type val2)
{ return (val1 > val2) ? val1 : val2; }
//----------------
//-- Updates max is newVal is greater than max
template <typename type>
inline void updateMax(type &max, type newVal)
{ if(max < newVal) max = newVal; }
//----------------
//-- Updates min is newVal is less than than min
template <typename type>
inline void updateMin(type &min, type newVal)
{ if(min > newVal) min = newVal; }
//----------------
//-- Used to avoid shitty error message g++ was giving me "error:
//-- call of overloaded 'abs(float)' is ambiguous"
template <typename type>
inline type ABS(type val)
{ return (val >= 0) ? val : -val; }
//----------------
//-- Will swap the two values around
//-- (i.e. the value in "val2" will end up in val1 and vice-versa)
template <typename type>
inline void swapVals(type &val1, type &val2) {
type tempVal = val1;
val1 = val2;
val2 = tempVal;
}
//----------------
//-- Will (if necessary) swap the values around such
//-- that val1 <= val2 will be true
template <typename type>
inline void swapValsAsc(type &val1, type &val2) {
if(val1 > val2) {
type tempVal = val1;
val1 = val2;
val2 = tempVal;
}
}
//----------------
//-- Will change val to min or max (whichever is closer)
//-- if it is outside of these two value.
template <typename type>
inline void keepWithinRange(type &val, type min, type max) {
if(val < min) val = min;
if(val > max) val = max;
}
//----------------
//-- Determines if val is between the two limit values, whereby
//-- the limit values are not necessarily in the order lowest, highest.
template <typename type>
inline bool isBetween(type limit1, type val, type limit2) {
return ((limit1 <= val && val <= limit2) || (limit2 <= val && val <= limit1));
}
//----------------
//-- Determines if val is between the two limit values (min & max) inclusive.
template <typename type>
inline bool isBetweenAsc(type min, type middle, type max) {
return (min <= middle && middle <= max);
}
//----------------
//-- Determines if val is between the two limit values NOT INCLUSIVE, whereby
//-- the limit values are not necessarily in the order lowest, highest.
template <typename type>
inline bool isBetweenNI(type limit1, type val, type limit2) {
return ((limit1 < val && val < limit2) || (limit2 < val && val < limit1));
}
//----------------
//-- Returns (positive) remainder between 0 and modVal (modVal not
//-- inclusive) after dividing value by modVal. Is equivalent to
//-- fmod(d1,d2), but seems to be faster.
inline float fMod(float val, float modVal) {
if(val >= modVal) {
int divisor = int(val / modVal);
return (val - divisor*modVal);
}
else if(val < 0) {
int divisor = (int)ceil(-val / modVal); //rounds up
return (val + divisor*modVal);
}
return (val);
}
//----------------
//-- Returns (positive) remainder between 0 and modVal-1. Unlike normal
//-- mod (%) this can handle negative numbers.
inline int intMod(int val, int modVal) {
if(modVal == 0) {
return (0);
}
else if(val >= modVal) {
return (val % modVal);
}
else if(val < 0) {
int divisor = (int)ceil(float(-val) / float(modVal)); // Rounds up
return (val + divisor*modVal);
}
return (val);
}
//----------------
//-- If values is outside min or max, it wraps it around so
//-- it is between the values using fMod
//-- EG: fModWithinRange (270, -180, 180) -> -90
//-- EG: fModWithinRange (4, 5, 10) -> 9
inline float fModWithinRange(float val, float min, float max) {
if(val >= min && val < max) {
return (val);
}
else {
return (fMod(val-min, max-min) + min);
}
}
//----------------
//-- Changes "val" by "increment", but prevents it from becoming any
//-- less than "min" or greater than "max".
inline void changeIntWithinRange(int &val, int min, int max,
int increment)
{
val = val + increment;
if(val < min) val = min;
if(val > max) val = max;
}
//----------------
//-- Changes/cycles "val" by "increment", while wrapping it around
//-- the edges so that it stays always remains between min and max.
inline void cycleIntWithinRange(int &val, int min, int max,
int increment)
{
val = val + increment;
val = intMod(val-min, max-min) + min;
}
//----------------
//-- Changes "val" by "increment", but prevents it from becoming
//-- any less than "min" or greater than "max".
template <typename type>
inline void changeNumWithinRange(type &val, type min, type max,
type changeAmount)
{
val = val + changeAmount;
if(val < min) val = min;
if(val > max) val = max;
}
//----------------
//-- Used to avoid divide by 0 error
inline float fDiv(float numerator, float denominator)
{
if(denominator == 0)
return FLOAT_MAX;
return numerator/denominator;
}
//----------------
//-- Used to avoid divide by 0 error
inline float fDivCustom(float numerator, float denominator,
float infinityValue)
{
if(denominator == 0)
return infinityValue;
return numerator/denominator;
}
//----------------
//-- Returns true if the given value is evenly divisible by the given divosor
inline bool isFactor(float value, float divisor)
{
float result = value / divisor;
return (result == (float)(floor(result)));
}
//----------------
//-- Rounds float to the nearest integer
inline int roundToInt(float x)
{
return int((x > 0.0) ? (x + 0.5) : (x - 0.5));
}
//----------------
//-- Founds float to nearest multiple of "precision"
inline float roundPrec(float value, float precision)
{
if(precision == 0)
return (value);
return (float)(roundToInt(value / precision) * precision);
}
//----------------
//-- Founds float to nearest multiple of "precision"
inline float roundDecimals(float value, int decimals)
{
float precision = pow(0.1f, (float)decimals);
return (float)(roundToInt(value / precision) * precision);
}
//----------------
//-- Averages two numbers.
inline float avg(float val1, float val2)
{
return (val1 + val2) / 2.0;
}
//----------------
//-- Finds the value "fractTowards2" along the way from val1 towards val2.
inline float getFractBetween(float val1, float val2,
float fractTowards2)
{
return (((val2 - val1) * fractTowards2) + val1);
}
//----------------
//-- Returns "numerator"/"denominator" as a percentage.
inline float calcPercent (float numerator, float denominator)
{
if(denominator==0)
return 100.0f;
float percent = (numerator / denominator) * 100.0f;
return percent;
}
//----------------
//-- Returns "numerator"/"denominator" as a percentage rounded to the nearest integer.
inline int calcPercentInt(float numerator, float denominator)
{
if(denominator==0)
return 100;
float percent = (numerator / denominator) * 100.0f;
return roundToInt(percent);
}
//----------------
//-- Returns "numerator"/"denominator" as a percentage rounded down to an integer.
inline int calcPercentFloor(float numerator, float denominator)
{
if(denominator==0)
return 100;
float percent = (numerator / denominator) * 100.0f;
return floor(percent);
}
//----------------------------------------------------------------------------
//## GEOMETRY FUNCTIONS:
//----------------------------------------------------------------------------
//----------------
//-- Keeps angle value between 0 and 360 (useful for functions like atan
//-- which may return a negative angle)
inline void keepAngleInRange(float &angle)
{ angle = (float)fMod(angle, 360); }
//----------------
//-- Calculates the volume of a sphere with given radius {4/3 PI r^3}
inline float geom_volumeSphere(const float radius)
{ return (4.0/3.0 * PI * (radius*radius*radius)); }
//----------------
//-- Calculates the surface area of a sphere with given radius {4 PI r^2}
inline float geom_surfaceAreaSphere(const float radius)
{ return (4.0 * PI * (radius*radius)); }
//----------------
//-- Calculates the volume of conical frustrum (a cylinder with different
//-- radius at either end) { 1/3*PI*h*(R^2*Rr*r^2) }
inline float geom_volumeConicalFrustrum(const float rBase, const float
rTop, const float height)
{ return (1.0/3.0 * PI * height * (SQ(rBase) + (rBase*rTop) + SQ(rTop))); }
//----------------
//-- Calculates the surface area of conical frustrum (a cylinder with
//-- different radius at either end)
//-- NOT including the areas of the circle at the base and at the top
inline float geom_surfaceAreaConicalFrustrum(const float rBase, const
float rTop, const float height)
{ return ( PI * (rBase+rTop) * sqrt(SQ((rBase-rTop)) + SQ(height)) ); }
//----------------
//-- Calculates the area of a circle given its radius {PI r^2}
inline float geom_areaCircle(const float radius)
{ return (PI * (radius*radius)); }
//----------------------------------------------------------------------------
//## STRING FUNCTIONS:
//----------------------------------------------------------------------------
//-------------
//-- Takes a single value of *almost* any type and returns it as a string
//-- by using ostringstream (string output stream).
//-- This function will also work for your own classes/structures, but only
//-- if you specify a "<<" operator.
//--
//-- FOR EXAMPLE: "friend ostream& operator<< (ostream &os, myPoint p)
//-- {os << pd.x << ',' << pd.y; return os;}"
template <typename type>
inline string toString(type value)
{
ostringstream out;
out << value;
return out.str();
}
//-------------
//-- Takes a number and converts to a string, but if it
//-- is < padLength digits long, then it will add extra characters
//-- ("0"'s by default) on the left of it if.
//--
//-- EXAMPLE: (value=5, padLength=4, padChar='0') -> return "0005"
template <typename data>
inline string toStringPadNumber(data value, int padLength, char padChar)
{
string returnStr = toString(value);
while((int)returnStr.length() < padLength)
returnStr = padChar + returnStr;
return returnStr;
}
//-------------
//-- Takes a number and adds commas (eg: 10000.05 -> 10,000.05)
template <typename data>
inline string toStringWithCommas(data value)
{
string str = toString(value);
int digitsBeforeDec = toString((int)value).length();
if(digitsBeforeDec <= 3)
return str;
int numCommasNeeded = ((digitsBeforeDec-1) / 3);
int leadingDigits = digitsBeforeDec - numCommasNeeded*3;
string returnStr = string_substr(str, leadingDigits, 0);
for(int i=0; i<numCommasNeeded; i++)
returnStr = returnStr + "," + string_substr(str, 3, leadingDigits+i*3);
return returnStr;
}
//-------------
//-- Takes a float and converts it to a string but limits the decimal places
inline string toString(float value, int decimal)
{
float exponent = (float)pow((float)10, (float)decimal);
float newValue = ((int)(value * exponent))/exponent ;
return toString(newValue);
}
//-------------
//-- Takes a string an returns a float by calling "atof" - which can
//-- handle the chars: '-', '.' and 'e' - eg: "-5.3e4" -> 53000).
//-- If there are bad characters 0 will be returned (maybe an error
//-- message should appear instead).
inline float string_getFloatFromString(string str) {
return (atof(str.c_str()));
}
//-------------
//-- Gets a substring (safely), from the start of a string.
inline string string_substr (string str, int chars, int offset)
{
if(offset >= (int)str.length() || offset < 0)
offset = (int)str.length();
if(chars + offset >= (int)str.length())
chars = (int)str.length() - offset;
return str.substr(offset, chars);
}
//-------------
//-- Gets a substring (safely), from the end of the string.
//-- EXAMPLE: ("myfile.jpg",3) -> "jpg"
inline string string_substrFromEnd (string str, int charsAtEnd)
{
if(charsAtEnd >= (int)str.length())
return str;
return str.substr((int)str.length()-charsAtEnd, charsAtEnd);
}
//-------------
//-- Returns true if the given haystack string STARTS with needle string.
//-- EXAMPLE: ("string", "str") -> true
inline bool string_startsWith (const string haystack, const string needle)
{
if(needle.length() > haystack.length())
return false;
for(int i=0; i<(int)needle.length(); i++)
if(haystack[i]!=needle[i])
return false;
return true;
}
//-------------
//-- Searches the string "str" Replaces ALL occurances of "searchStr" and replaces them with "replaceStr"
//-- EXAMPLE: ("now or forever", "or", "|") -> "now | f|ever"
inline string string_replace (string str, const string searchStr, const string replaceStr)
{
if(searchStr == replaceStr || str == "" || searchStr == "")
return str;
string::size_type pos = 0;
while((pos = str.find(searchStr, pos)) != string::npos)
str.replace(pos, searchStr.size(), replaceStr);
return str;
}
//-------------
//-- Eliminates ALL immediate repeats of the same needle string inside the haystack string.
//--
//-- EXAMPLE: ("Spaces are bad", " " ) -> "Spaces are bad"
//-- EXAMPLE: ("I am am am bad", "am ") -> "I am bad"
inline string string_eliminateDuplicates(const string haystack, const string needle) {
return string_replace(haystack, needle+needle, needle);
}
//-------------
//-- Takes a string and splits it apart anywhere the explodeStr appears (not inclusive), thus forming a vector of smaller strings.
//--
//-- eg: input: ("one|two|three", "|") -> returns: vector("one", "two", "three")
inline vector<string> string_explode(string str, string explodeStr) {
vector<string> ret;
int iPos = (int)str.find(explodeStr, 0);
int iPit = (int)explodeStr.length();
while(iPos > -1) {
if(iPos!=0)
ret.push_back(str.substr(0,iPos));
str.erase(0,iPos+iPit);
iPos = (int)str.find(explodeStr, 0);
}
if(str!="")
ret.push_back(str);
return ret;
}
//-------------
//-- Calls string_explode and returns the specified argument (element) in the vector.
//-- If there are less than argNum elements an empty string is returned.
//-- NOTE: If eliminateDuplicates is true then any empty "arguments" are removed before chosing.
//--
//-- EXAMPLE: ("one/two/three", "/", 2, false) -> returns "two"
inline string string_explodeGetArgument(string str, string sepStr, int argNum,
bool eliminateDuplicates)
{
if(eliminateDuplicates)
str = string_eliminateDuplicates(str, sepStr);
vector<string> strVec = string_explode(str, sepStr);
return (argNum>(int)strVec.size()) ? ("") : (strVec.at(argNum-1));
}
//--------------------------------------------------------------------------------------------------
//## RANDOM NUMBER FUNCTIONS:
//--------------------------------------------------------------------------------------------------
//----------------
//-- The following functions return random coefficients, but differ in resulotion
//-- and wether or not 1 is inclusive.
//--
//-- NOTE: RAND_MAX = 32767. This isn't enough granularity for all purposes, in which case one
//-- of the two "high res" functions should be used. These provide a granulatiry of approx
//-- 1E9 (1 billion possible coefficient values).
//--
//-- WARNING: Before calling these, make sure the rand function is seeded by
//-- calling srand(time(0));
#include <time.h> // for time_t and clock_t;
const double RAND_MAX_D = double(RAND_MAX); // The largest value generated by rand() as a double.
const double RAND_MAX_HIGH_RES_D = RAND_MAX_D*RAND_MAX_D + RAND_MAX_D; // The largest value generated by highResRand() as a double.
inline void seedRandom() { //-- Seeds all future generation of random numbers using rand().
srand((int)time(0));
}
inline double highResRand() { //-- Returns a high resolution random value between 0 and 1,073,709,056 as a double.
return ((double(rand())*double(RAND_MAX)) + double(rand()));
}
inline double randCoef() { //-- Returns a low resolution random coefficients: 0<=value<=1.
return rand() /RAND_MAX_D;
}
inline double randCoefOneNotInclusive() { //-- Returns a low resolution random coefficients: 0<=value<1.
return rand() / (RAND_MAX_D+0.1);
}
inline double randHighResCoef() { //-- Returns a high resolution random coefficients: 0<=value<=1.
return highResRand() / RAND_MAX_HIGH_RES_D;
}
inline double randHighResCoefOneNotInclusive() { //-- Returns a high resolution random coefficients: 0<=value<1.
return highResRand() / (RAND_MAX_HIGH_RES_D + 1.0);
}
inline double randDbl(double min, double max) { //-- Returns a high resolution random double between min and max .
return double(min + (randHighResCoef() * (max - min))); // (NOTE: if max is 2, then it won't return a value higher than 2).
}
inline int randIntInclusive(int min, int max) { //-- Returns a high resolution random integer between min and max inclusive.
return int((randHighResCoefOneNotInclusive() * double(max-min+1)) + double(min));
}
inline float randFlt(float min, float max) { //-- Returns a low resolution random float between min and max.
return float(min + ((rand()/RAND_MAX_D) * (max - min))); // (NOTE: if max is 2, then it won't return a value higher than 2).
}
//--------------------------------------------------------------------------------------------------
//## TIME FUNCTIONS:
//--------------------------------------------------------------------------------------------------
#include <time.h> // for time_t and clock_t;
//-------------
//-- Returns a string for a timestamp value in the form: "06/24/04 14:10:40" (which can be interpreted by excel)
inline string time_getCurrTimeStampString()
{
char timestamp[30];
time_t currTime = time(0);
strftime(timestamp,30,"%x %X",localtime(&currTime)); // Get timeStamp (eg: "06/24/04 14:10:40").
return timestamp;
}
//-------------
//-- Returns a string for a timestamp value in the form: "Thu_06/24/04_14:10:40"
inline string time_getCurrTimeStampStringWithUnderscores()
{
char timestamp[30];
time_t currTime = time(0);
strftime(timestamp,30,"%a_%x_%X",localtime(&currTime)); // Get timeStamp (eg: "Thu_06/24/04_14:10:40").
return timestamp;
}
//-------------
//-- Returns the current time in seconds, as a long
inline long time_getCurrTimeInSecs()
{
time_t currTime = time(0);
return long(currTime);
}
//-------------
//-- Takes the numbers of seconds elapsed and formats a string in the form: "1 hrs 9 mins 23 secs" or "1:09 s" if simpleFormat is true
inline string time_formatTimeElapsed(long secsElapsed, bool includeSecs, bool simpleFormat)
{
int hours = int(secsElapsed / 3600);
secsElapsed = secsElapsed - (hours*3600);
int minutes = int(secsElapsed / 60);
int seconds = secsElapsed - (minutes*60);
string formatted = ((hours) ? toString(hours) + " hrs " : "") + toString(minutes) + " mins " + ((includeSecs) ? toString(seconds) + " secs" : "");
if(simpleFormat)
formatted = toString(hours) + ":" + toStringPadNumber(minutes, 2);
return(formatted);
}
//----------------------------------------------------------------------------
//## VECTOR RELATED FUNCTIONS:
//----------------------------------------------------------------------------
//-------------
//-- Takes a two dimensional vector and reverses the order of the dimensions.
//-- for example:
//--- { {0,1,2},
//-- {3,4,5} }
//-- would become:
//-- { {0,3},
//-- {1,4},
//-- {2,5} }
//--
//-- NOTE: If any of the second dimension are DIFFERENT lengths,
//-- then returns false.
template <typename type>
bool vector2D_transpose(vector< vector<type> > &v)
{
if(v.empty() || v[0].empty())
return false;
int DIM_X = (int)v.size();
int DIM_Y = (int)v[0].size();
//## CHECK ALL VECTORS (IN THE MAIN VECTOR) ARE SAME SIZE:
for(int x=1; x<DIM_X; x++)
if(v[x-1].size() != v[x].size())
return false;
//## CREATE TRANSPOSED VERSION:
vector< vector<type> > vT;
vT.resize(DIM_Y);
for(int x=0; x<DIM_Y; x++)
vT[x].resize(DIM_X);
for(int x=0; x<DIM_X; x++)
for(int y=0; y<DIM_Y; y++)
vT[y][x] = v[x][y];
v = vT;
return true;
}
//-------------
//-- Eliminates duplicates from a vector, but ONLY if they
//-- occur sequentially - hence user should sort the vector first.
//--
//-- EXAMPLE 1: {1,3,3,3,5} -> the second two 3's will be removed
//-- EXAMPLE 1: {3,1,3,5,3} -> no elements will be removed :(
template <typename type>
void vector_eliminateDuplicates(vector<type> &v)
{
for(int i=1; i<(int)v.size(); i++)
if(v[i-1]==v[i])
{
v.erase(v.begin()+i);
--i;
}
}
//-------------
//-- Checks if element already exists
template <typename type>
inline bool vector_doesElementExistInVector(vector<type> v, type element)
{
for(int i=0; i<(int)v.size(); i++)
if(element == v.at(i)) {
return (true);
}
return (false);
}
//-------------
//-- Appends the contents of the second vector to the end of
//-- the first vector and returns the result
template <typename type>
vector<type> vector_concat(vector<type> &v1, vector<type> &v2)
{
vector<type> returnVec = v1;
for(int i=0; i<(int)v2.size(); i++)
returnVec.push_back(v2[i]);
return returnVec;
}
//-------------
//-- Sorts given vector in ascending order, starting with
//-- the elment at the index startIdx
template <typename type>
inline vector<type> vector_sort(vector<type> v, int startIdx, int endIdx)
{
if(startIdx < 0)
startIdx = 0;
if(endIdx > (int)v.size()-1)
endIdx = (int)v.size()-1;
#if defined (__APPLE__)
// NOTE: For some reason the "sort()" command doesn't work on OSX, so
// I've had to write my own heap sort (RECENTLY MODIFIED SO NOT CHECKED)
int n; // Current last element on heap.
for(n=startIdx; n<=endIdx; n++) //## Build heap by doing a "siftup" on each new element:
{
int i=n; // The newest element added to heap.
int p=(n-startIdx)/2; // its parent
for(; p>=0 && v[i] > v[p]; i=p, p=(i-startIdx)/2) // While bigger than parent: swap.
swap(v[i], v[p]);
}
for(n=endIdx; n>=startIdx;) //## Deconstruct heap by moving max element to the end and doing a "siftdown":
{
swap(v[startIdx], v[n--]); // Move max element to the end.
int i = startIdx; // Current element to "siftdown".
int c = i+1; // First child of current element.
for(; c<=endIdx; i=c, c=(c-startIdx)*2)
{
if(c+1<=endIdx && v[c+1] > v[c]) // If other child is bigger: use this child.
c++;
if(v[i] >= v[c] ) // If node is bigger than parent: stop.
break;
swap(v[c], v[i]); // Else swap with child and continue.
}
}
return v;
#else
sort(v.begin()+startIdx, v.begin()+endIdx);
return v;
#endif
}
//-------------
//-- Sorts given vector in ascending order (from first to last element)
template <typename type>
vector<type> vector_sort(vector<type> v)
{
#if defined (__APPLE__)
return vector_sort(v, 0);
#else
vector<type> returnVec = v;
sort(returnVec.begin(), returnVec.end());
return returnVec;
#endif
}
//-------------
//-- Reverses the order of elements from "startIdx" to "endIdx" inclusive
template <typename type>
inline vector<type> vector_reverse(vector<type> v, int startIdx, int endIdx)
{
if(startIdx < 0)
startIdx = 0;
if(endIdx > (int)v.size()-1)
endIdx = (int)v.size()-1;
vector<type> returnVec;
for(int i=0; i<startIdx; i++)
returnVec.push_back(v[i]);
for(int i=startIdx; i<=endIdx; i++)
returnVec.push_back(v[endIdx-(i-startIdx)]);
for(int i=endIdx+1; i<(int)v.size(); i++)
returnVec.push_back(v[i]);
return returnVec;
}
//----------------------------------------------------------------------------
//## VECTOR RELATED FUNCTIONS:
//----------------------------------------------------------------------------
//-------------
//-- Loads all lines of text from the text file into a vector of strings.
inline vector<string> file_loadTextFromFile(string filePath, bool printStatus)
{
const int MAXLINEFORREADING = 2048;
vector<string> text;
char line[MAXLINEFORREADING];
//## OPEN TEXT FILE FOR INPUT:
if(printStatus)
cout << "Opening file '" << filePath << "'" << endl;
FILE *fp = fopen(filePath.c_str(), "r");
if(fp == NULL)
{
if(printStatus)
cout << "ERROR: Opening of file '" << filePath << "' failed." << endl;
return text;
}
while (fgets(line, MAXLINEFORREADING, fp) != NULL)
text.push_back(line);
if(fp != NULL)
fclose(fp);
return text;
}
//-------------
//-- Saves a string to the file, and returns true if successful
inline bool file_saveStringToFile(string filePath, string text, bool append=false)
{
//## OPEN TEXT FILE FOR WRITING:
FILE *fp = (append) ? fopen(filePath.c_str(), "a") : fopen(filePath.c_str(), "w");
if(fp == NULL)
{
cout << "ERROR: Opening of file '" << filePath << "' failed." << endl;
return false;
}
fputs(text.c_str(), fp);
if(fp != NULL)
fclose(fp);
return true;
}
//----------------------------------------------------------------------------
#endif