Removing references of SongsPk.info from downloaded bollywood songs

If you are a software engineer from India, you must have downloaded Bollywood songs from Songspk.info or one of its clone sites at least once. Its a nice service for sure but they definitely have their own quirks. Checking the music file in Windows explorer or Media player will show songspk.info in multiple place including in file names and all the tags. They definitely deserve to do it given the service they provide but I intend to remove that information from downloaded files to keep them short and clean in my media players and hence decided to use Powershell for some automation. Result of that effort is as follows

Before using this, make sure to download taglib-sharp on some folder as it needs to be loaded. Before running any command, make sure to run it with -Whatif parameter to understand what it will do. Code is divided into 3 sections. I intend to add function for modifying tags with multiple values later on. I am greatly indebted to all bloggers on powershell and especially stackoverflow for helping me along the way. They are too many to list out here.


Function Check-TagLibLoad()
{

#validate if taglib-sharp is loaded or not
$taglibload = [System.AppDomain]::CurrentDomain.GetAssemblies() | `
Select-Object -Property FullName | `
Select-String -Pattern "taglib-sharp"
if (!$taglibload){
Throw "Load Taglib using [Reflection.assembly]::LoadFrom(<Full path of downloaded taglib-sharp dll like D:\temp\taglib-sharp-2.1.0.0-windows\Libraries\taglib-sharp.dll>)"
}
}

Function Rearrange-Patterns()
{
# Rearranges array so that if string A is part of B, A comes after B
Param(
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[String[]]$Patterns
)
[System.Collections.Generic.List[System.String]]$PatternsTemp = $Patterns | Sort-Object -Unique
for ($cnt1 = 1; $cnt1 -lt $PatternsTemp.Count; $cnt1++){
do{
$found = $false
for ($cnt2 = 0; $cnt2 -lt $cnt1; $cnt2++){
if ($PatternsTemp[$cnt1].Length -le $PatternsTemp[$cnt2].Length){
continue
}
if ($PatternsTemp[$cnt1] -match $PatternsTemp[$cnt2]){
$PatternsTemp.Insert($cnt2,$PatternsTemp[$cnt1])
$PatternsTemp.RemoveAt($cnt1+1)
$found = $true
break
}
}
}while($found -eq $true)
}
$PatternsTemp
}
# Rearrange-Patterns -Patterns "Songspk.info","songs","- Songspk.info","so","pk","info","Songspk","[Songs]"

This function uses above two functions. Save all three in one file and then dot source that file and use this function through pipe lining. Make sure to run with -WhatIf first and carefully examine output.

Function Update-Simple-tags()
{

# Update tags with simple non-array values
[CmdletBinding()]
Param(
[ValidateNotNullOrEmpty()]
[Parameter( Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('FullName')]
[String[]]$FilePath,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string[]]$RemovePatterns,
[switch]$WhatIf
)
begin{
Check-TagLibLoad
$RemovePatterns = Rearrange-Patterns -Patterns:$RemovePatterns
}
Process
{
Unblock-File -LiteralPath:$FilePath

$Music = [taglib.file]::create($FilePath)
$TagList = @("Title", "Comment", "Lyrics", "Conductor", "Copyright")
$Update = $False
$Message = @("$FilePath")

foreach ($tag in $taglist)

{
$OldTagVal = $Music.tag.$tag
$RemovePatterns | ?{$Music.tag.$tag -Match $_} |

%{
$Music.tag.$tag = ($Music.tag.$tag -replace $_, "").Trim()
$Update = $true
}
if ($update -eq $true) {
$Message += (" '$Tag': '$OldTagVal' to '"+$Music.tag.$tag+"'")}
else{
$Message += (" '$Tag': No Update")
}
$Update = !($Whatif)
}
if ($Update -eq $true) {
$Music.save()
}
$Message
}
End{
}
}

# dir -filter 2015* -Directory | %{dir -Path $_ -Filter *.mp3 -File} | Update-Simple-tags -RemovePatterns "Songspk.info","- Songspk.info","www.SongsPk.Info" -WhatIf  | Out-File Update.log
# dir -filter 2015* -Directory | %{dir -Path $_ -Filter *.mp3 -File} | Update-Simple-tags -RemovePatterns "Songspk.info","- Songspk.info","www.SongsPk.Info" | Out-File Update.log

Below are some commands that can be used to edit downloaded files before running above functions to ensure files are in good naming convention to be modified. Names with ‘[‘ in them are tough to handle otherwise. Unblocking is needed since files are downloaded from internet. Rename-Item cannot work with file with special characters hence Move-Item. Make sure to use -WhatIf beforehand with each command. There is a blog post that talks about unzipping zipped file from Powershell but you can discover that if needed.

#Dir -Filter 2015-*.zip | Unblock-File
#Dir -Filter 2016* -Directory | Move-Item -Destination {$_.FullName -replace "320kbps",""}
#Dir -Filter 2016* -Directory | Move-Item -Destination {$_.FullName -replace "\[Songspk.info\]",""}
#Dir -Filter *-2015.zip | Move-Item -Destination {"2015-"+($_.Name -replace "-2015","")}
#Dir -Filter 2016* -Directory | %{dir -Path $_ -recurse -File} | Move-Item -Destination {$_.FullName -replace "\[Songspk.info\] ",""}
#Dir -Filter *2016* -Directory | | Move-Item -Destination {$_.Name -replace "\[Songspk.info\] ",""}
#[Reflection.Assembly]::LoadFrom("D:\temp\taglib-sharp-2.1.0.0-windows\Libraries\taglib-sharp.dll")

Time zone of a tweet

It took me considerable time for me to decipher, but I finally managed to figure out few idiosyncrasies about Timezones used in a tweet. Twitter uses a simple mechanism when displaying tweet time to you on Twitter.com.

  • If you are logged in, time shown will be of Timezone set in your profile.
  • If you are not logged in, time will be shown in San francisco, USA timezone which is local timezone of twitter HQ.

At no time, it seems to care for system timezone.

As per some research, apparently, it saves the information in the database in GMT based values, but even APIs return values converted to profile timezone. Second case will not occur with API usage since Non-logged in user cannot call API directly. APIs do not seems to save daylight saving information so that will need to be deduced. It though contains UTC offset but its of the API caller not tweet poster. This thus rules out possibility of deducing location through timezone data if location info is not shared by Tweet poster.

To convert time of a tweet to the time of a location, various tools can be used. Most useful seems like https://www.timeanddate.com/worldclock/converter.html . You can provide multiple target cities in this one.

To avoid doing all this, you can use storify.com and copy the tweet there after creating an account and editing default story. Its settings allows one to change timezone of a story to the timezone of your target tweets thus giving this whole information easily.

Using Sendgrid with Powershell

Create a sendgrid account at https://sendgrid.com/

Download nuget.exe from https://www.nuget.org/nuget.exe and save it in some folder where sendgrid will be installed.

Run ‘nuget.exe install sendgrid’ on command line from the path where nuget.exe is saved. Two sendgrid folders will be created with structure like below in the same directory from where the command is run. No need to use Run as administrator option.

  • Sendgrid.6.1.0\lib\SendGridMail.dll
  • Sendgrid.6.1.0\Sendgrid.6.1.0.nupkg
  • SendGrid.SmtpApi.1.3.1\lib\net40\SendGrid.SmtpApi.dll
  • SendGrid.SmtpApi.1.3.1\lib\portable-net4+wp81\SendGrid.SmtpApi.dll
  • SendGrid.SmtpApi.1.3.1\SendGrid.SmtpApi.1.3.1.nupkg

These folders are downloaded by nuget from https://github.com/sendgrid/sendgrid-csharp which is official location for SendGrid C# libraries.

This install option will not add these assemblies to GAC so you will need to use either Add-Type or [Reflection.Assembly]::LoadFrom(…)  option to load these libraries in session or script. Overall Code would be like below

$SGMail= [Reflection.Assembly]::LoadFile("C:\Software\Sendgrid.6.1.0\lib\SendGridMail.dll")
$SGSMTP= [Reflection.Assembly]::LoadFile("C:\Software\SendGrid.SmtpApi.1.3.1\lib\net40\SendGrid.SmtpApi.dll")</code>

$myMessage = New-Object -TypeName:SendGrid.SendGridMessage
$myMessage.From = New-Object System.Net.Mail.MailAddress("user@example.com");
$recipients = @("Another user &lt;Anotheruser@AnotherDomain.com&gt;")
$myMessage.AddTo($recipients);
$myMessage.Subject = "Testing the SendGrid Library"

$myMessage.Html = "&lt;p&gt;Hello World!&lt;/p&gt;"
$myMessage.Text = "Hello World plain text!"

$username = "sendgridusername"
$password = "sendgriduserpassword"
$credentials = New-Object -TypeName:System.Net.NetworkCredential -ArgumentList:$username,$password

$TransportWeb = New-Object -TypeName:Sendgrid.web -ArgumentList:$credentials
$returnval = $TransportWeb.DeliverAsync($myMessage)
$returnval

Easiest way to figure out the exported classes from Sendgrid DLLs is to load these as reference in a VS 2015 VC# windows console app where you can then use Object browser to access all classes exported by these DLLs. Powershell has a convoluted way to show that but no point wasting time behind that when VS Community 2015 is free for all.

Definitely, this is not most secure code, but it works. Also, do remember that using this for internal organizational mails may be security risk since Sendgrid SMTP server would be transmitting it and thus they can have access to all your mails.

two Sendgrid classes used here are Sendgrid.sendgridmessage and Sendgrid.web. System.web is not getting used as that may seem look like from Sendgrid Github example.

Workflows for document sharing knowledge world

Converting Web pages on Android to PDF document

  1. Install Mozilla Firefox for Android and Adobe Acrobat Reader.
  2. Open web page in Firefox after clicking on link or typing it. If it opens in default browser, copy the link and paste it in Firefox address bar.
  3. Open Firefox menu and go to Page->’Save as PDF’.
  4. Conversion process will start indicating a download is in progress.
    1. If not interested in actual page layout, try to open page in Firefox read mode if its available.
  5. Downloaded PDF file should be in the downloads folder or show in notification center.
  6. Open file in PDF viewer or select it in downloads folder.
  7. Use sharing option to upload it to favorite cloud folder, Google drive, Microsoft OneDrive or Dropbox.

If links are in Pocket App

  1. Open pocket app or http://GetPocket.com and open the desired item saved earlier.
  2. Click on sharing button. If needed, click on more until you see Firefox in list. Alternatively, copy to clipboard and then paste it in Firefox.
  3. Further action as above.
  4. Converting on PC needs Bullzip or HTML2PDF and quiet time taking process. You can simply save page link in Pocket and then later on do PDF conversion on mobile in free time.

Link saving through Twitter

If you have very active twitter feed, lot of information may be scrolling and many with links. While going through them quickly, it is not easy to read through all of them and we may even forget about good things. Pocket by ‘Read It later’ comes handy in this case.

  1. Open tweet in twitter app and click on sharing option.
  2. Ins haring dialogue box, Use ‘Save to Pocket’ or ‘Google Keep’ or ‘Onenote’ option.
    1. I like pocket better than others. Other two simply create a new note.
  3. If this does not work, simply use ‘copy to clipboard’ from sharing option but it is suboptimal and copies the who tweet with shortened link. ‘Save to Pocket’ saves link embedded in the Tweet instead of tweet message. It saves tweet also but its display is intelligent to show inside links. If no inside link is there, it shows tweet.

This allows to move content between multiple devices. Pocket account and app can be created and installed on Desktop and other places. Firefox is now having native support for it.

Useful Information

A string tokenizer class in C++

Many a times, we need to tokenize various inputs and other data and end up writing custom code for each use. I have tried to make it more generic using latest C++11 STL facilities. Given that its a template class, make sure to copy the whole code in a header file for use across the project. std::wstring and std:;string both can be passed as template argument.

A simple use is as follows

Tokenizer<std::wstring>(m_delims, TokenizerOP::SIMPLE).GetTokens(m_input, tokens);

auto tokens_1 = Tokenizer<std::wstring>(m_delims, TokenizerOP::SIMPLE).GetTokens(m_input);

Tokenizer code is as follows

///////////////////////////////////////////////////////////////////////////////
// Tokenizer
enum class TokenizerOP
{
	SIMPLE,
	TRIMMEDTOKENS, NONEMPTYTOKENS, NONEMPTYTRIMMEDTOKENS,
	UNIQUETOKENS, UNIQUETRIMMEDTOKENS,
	UNIQUENONEMPTYTOKENS, UNIQUENONEMPTYTRIMMEDTOKENS
};
template <typename valueType>
class Tokenizer
{
private:
	TokenizerOP			op_;
	valueType			delims_;

	valueType
	Trim(valueType const &s)
	{
		auto  wsfront = std::find_if_not(s.begin(), s.end(), 
					[](int c){return std::isspace(c); });
		return valueType(wsfront,
			std::find_if_not(s.rbegin(), valueType::const_reverse_iterator(wsfront),
			[](int c){return std::isspace(c); }).base());
	}
	void
	TrimTokens(std::vector<valueType>& tokens)
	{
		for (size_t i = 0; i < tokens.size(); i++)
			tokens[i] = Trim(tokens[i]);
	}
	void
	RemoveEmptyTokens(std::vector<valueType>& tokens)
	{
		using namespace std;
		vector<valueType> nonemptytokens;

		for (auto &it : tokens){
			auto  wsfront = find_if_not(it.begin(), it.end(), [](int c){return std::isspace(c); });
			if (it.end() != wsfront){
				nonemptytokens.push_back(it);
			}
		}
		if (tokens.size() != nonemptytokens.size())
			tokens = nonemptytokens;
	}
	void
	KeepUniqueTokens(std::vector<valueType>& tokens)
	{
		using namespace std;
		if (tokens.size() <= 1)
			return;

		vector<valueType> UniqueTokens;
		UniqueTokens.push_back(tokens.front());
		for (auto it = tokens.begin() + 1; it != tokens.end(); it++){
			if (it == find(tokens.begin(), it, *it))
				UniqueTokens.push_back(*it);
		}
		if (tokens.size() != UniqueTokens.size())
			tokens = UniqueTokens;
	}

public:
	Tokenizer() :Tokenizer(TokenizerOP::SIMPLE){}
	Tokenizer(TokenizerOP op) : op_(op){}
	Tokenizer(valueType const& delims, TokenizerOP op = TokenizerOP::SIMPLE)
		:delims_(delims), op_(op){};

	std::vector<valueType>
	Tokens(valueType const& text)
	{
		std::vector<valueType> tokens;
		GetTokens(text, tokens);
		return tokens;
	}
	std::vector<valueType>
	Tokens(valueType const& text, valueType const& delims)
	{
		delims_ = delims;
		return Tokens(text);
	}
	std::vector<valueType>
	Tokens(valueType const& text, TokenizerOP op)
	{
		op_ = op;
		return Tokens(text);
	}
	void
	GetTokens(valueType const& text, std::vector<valueType>& tokens)
	{
		using namespace std;
		tokens.clear();
		valueType::size_type lastPos = text.find_first_not_of(delims_, 0);
		valueType::size_type pos = text.find_first_of(delims_, lastPos);

		while (valueType::npos != pos || valueType::npos != lastPos){
			tokens.push_back(text.substr(lastPos, pos - lastPos));
			lastPos = text.find_first_not_of(delims_, pos);
			pos = text.find_first_of(delims_, lastPos);
		}

		if (TokenizerOP::TRIMMEDTOKENS == op_){
			TrimTokens(tokens);
		}
		if (TokenizerOP::NONEMPTYTOKENS == op_){
			RemoveEmptyTokens(tokens);
		}
		if (TokenizerOP::NONEMPTYTRIMMEDTOKENS == op_){
			TrimTokens(tokens);
			RemoveEmptyTokens(tokens);
		}
		if (TokenizerOP::UNIQUETOKENS == op_){
			KeepUniqueTokens(tokens);
		}
		if (TokenizerOP::UNIQUETRIMMEDTOKENS == op_){
			TrimTokens(tokens);
			KeepUniqueTokens(tokens);
		}
		if (TokenizerOP::UNIQUENONEMPTYTOKENS == op_){
			KeepUniqueTokens(tokens);
			RemoveEmptyTokens(tokens);
		}
		if (TokenizerOP::UNIQUENONEMPTYTRIMMEDTOKENS == op_){
			TrimTokens(tokens);
			KeepUniqueTokens(tokens);
			RemoveEmptyTokens(tokens);
		}
		return;
	}

	void
	GetTokens(
		valueType const& text, 
		std::vector<valueType>& tokens,
		valueType const& delims)
	{
		delims_ = delims;
		GetTokens(text, tokens);
		return;
	}
};

A basic extensible execution timer for C++

All of us need to time our projects and part of it. While recently getting re-acquainted with C++ through C++11, I too need to do it many times. I started with a using std::chrono facilities, but soon figured out that changing code to track different time of operations was getting tiring and boring. Some portions makes meaning only when expressed in seconds and some would never reach second limits and we are better off tracing them in microseconds. Then again, microseconds may go into 7-8 digits and we woul have tpough time comparing two values if log file has multiple outputs. I thus decided to revamp my timerclass and wrote its signature as follows. Its usage is shown in the blog here.

////////////////////////////////////////////////////////////////////////////////
class PrintTimer
{
public:
virtual std::wstring
	to_wstring(std::chrono::hours::rep value, std::chrono::hours dummy) = 0;
virtual std::wstring
	to_wstring(std::chrono::minutes::rep value, std::chrono::minutes dummy) = 0;
virtual std::wstring
	to_wstring(std::chrono::seconds::rep value, std::chrono::seconds dummy) = 0;
virtual std::wstring
	to_wstring(std::chrono::microseconds::rep value, std::chrono::microseconds dummy) = 0;
virtual std::wstring
	to_wstring(std::chrono::milliseconds::rep value, std::chrono::milliseconds dummy) = 0;
};

template<typename clock_type, typename dur>
class ExecutionTimer
{
private:

typename clock_type::time_point m_start;
typename clock_type::time_point m_end;
std::shared_ptr<PrintTimer>		m_printer;

public:

ExecutionTimer() : ExecutionTimer(nullptr) {};
ExecutionTimer(std::shared_ptr<PrintTimer> const& printer)
{
	m_start = clock_type::now();;
	m_end = clock_type::now();;
	m_printer = printer;
};

void set_start(){
	m_start = clock_type::now();
}
void set_start(typename clock_type::time_point start){
	m_start = start;
}
void set_end(){
	m_end = clock_type::now();
}
void set_end(typename clock_type::time_point end){
	m_end = end;
}
void set_printer(std::shared_ptr<PrintTimer> const& printer){
	m_printer = printer;
}

typename dur::rep elapsed()
{
	return std::chrono::duration_cast<dur>(m_end - m_start).count();
};
std::wstring to_wstring(){
	return to_wstring(m_printer);
}
std::wstring to_wstring(std::shared_ptr<PrintTimer> const& printer)
{
	if (printer){
		auto ret = printer->to_wstring(elapsed(), 
			std::chrono::duration_cast<dur>(std::chrono::seconds(1)));
		return ret;
	}
	else{
		return L"Printing facilities not available";
	}	
}
};

PrintTimer is the interface that will be used to display output in nice way when its big. You will see it soon. ExecutionTimer has to be declared and defined fully in a header file for it to be available everywhere as it is a template class for std::chrono facilities. The whole shebang here will not use C library functions for timer display which was the main agenda. Everything is done using STL methods. Purpose of having PrintTimer as interface is very simple, it allows these big functions to be written anywhere and in customizable way. If user does not need it, then can simply call elapsed from ExecutionTimer and get the abstract counter and then use some other display scheme.

dummy parameters at the end of each to_wstring method is needed to ensure function overloading since multiple ***::rep values coalesces to same kind.

My implementation for PrintTimer interface is as follows.

////////////////////////////////////////////////////////////////////////////////
class PrintExecutionTimer :public PrintTimer
{
private:
const std::wstring SS = std::wstring(L" ");

public:
virtual std::wstring
	to_wstring(std::chrono::hours::rep value, std::chrono::hours dummy);
virtual std::wstring
	to_wstring(std::chrono::minutes::rep value, std::chrono::minutes dummy);
virtual std::wstring
	to_wstring(std::chrono::seconds::rep value, std::chrono::seconds dummy);
virtual std::wstring
	to_wstring(std::chrono::microseconds::rep value, std::chrono::microseconds dummy);
virtual std::wstring
	to_wstring(std::chrono::milliseconds::rep value, std::chrono::milliseconds dummy);
};

////////////////////////////////////////////////////////////////////////////////
std::wstring
PrintExecutionTimer::to_wstring(std::chrono::hours::rep value, std::chrono::hours dummy)
{
	using namespace std::chrono;
	auto ret = std::to_wstring(value) + SS + L"hours";
	return ret;
}
std::wstring
PrintExecutionTimer::to_wstring(std::chrono::minutes::rep value, std::chrono::minutes dummy)
{
	using namespace std::chrono;
	std::wstring ret{ L"" };
	auto cmp_unit = minutes(60).count();
	auto dummy_to_pass = duration_cast<hours>(dummy);

	if (value > cmp_unit){
		ret = to_wstring(hours::rep(value / cmp_unit), dummy_to_pass);
		ret += SS + std::to_wstring(value % cmp_unit) + SS + L"minutes";
	}
	else if (value == cmp_unit){
		ret = to_wstring(hours::rep(1), dummy_to_pass);
	}
	else{
		ret = std::to_wstring(value) + SS + L"minutes";
	}
	return ret;
}

std::wstring
PrintExecutionTimer::to_wstring(std::chrono::seconds::rep value, std::chrono::seconds dummy)
{
	using namespace std::chrono;
	std::wstring ret{ L"" };
	auto cmp_unit = seconds(60).count();
	auto dummy_to_pass = duration_cast<minutes>(dummy);

	if (value > cmp_unit){
		ret = to_wstring(minutes::rep(value / cmp_unit), dummy_to_pass);
		ret += SS + std::to_wstring(value % cmp_unit) + SS + L"seconds";
	}
	else if (value == cmp_unit){
		ret = to_wstring(minutes::rep(1), dummy_to_pass);
	}
	else{
		ret = std::to_wstring(value) + SS + L"seconds";
	}
	return ret;
}

std::wstring
PrintExecutionTimer::to_wstring(std::chrono::milliseconds::rep value, std::chrono::milliseconds dummy)
{
	using namespace std::chrono;
	std::wstring ret{ L"" };
	auto cmp_unit = milliseconds(1000).count();
	auto dummy_to_pass = duration_cast<seconds>(dummy);

	if (value > cmp_unit){
		ret = to_wstring(seconds::rep(value / cmp_unit), dummy_to_pass);
		ret += SS + std::to_wstring(value % cmp_unit) + SS + L"milliseconds";
	}
	else if (value == cmp_unit){
		ret = to_wstring(seconds::rep(1), dummy_to_pass);
	}
	else{
		ret = std::to_wstring(value) + SS + L"milliseconds";
	}
	return ret;
}

std::wstring
PrintExecutionTimer::to_wstring(std::chrono::microseconds::rep value, std::chrono::microseconds dummy)
{
	using namespace std::chrono;
	std::wstring ret{ L"" };
	auto cmp_unit = microseconds(1000).count();
	auto dummy_to_pass = duration_cast<milliseconds>(dummy);

	if (value > cmp_unit){
		ret = to_wstring(milliseconds::rep(value / cmp_unit), dummy_to_pass);
		ret += SS + std::to_wstring(value % cmp_unit) + SS + L"microseconds";
	}
	else if (value == cmp_unit){
		ret = to_wstring(milliseconds::rep(1), dummy_to_pass);
	}
	else{
		ret = std::to_wstring(value) + SS + L"microseconds";
	}
	return ret;
}

You may notice that they reference each other. If needed, you can decouple them from each other.

Below is a use case as to how to use it.

void timer_test()
{
    using namespace std::chrono;
	using namespace std;

	ExecutionTimer<high_resolution_clock, microseconds> exe_timer_micro;
	ExecutionTimer<high_resolution_clock, milliseconds> exe_timer_milli(new PrintExecutionTimer());
	exe_timer_micro.set_start();
	exe_timer_milli.set_start();

	for (size_t i = 0; i < (std::numeric_limits<unsigned int>::max()); i++)
	{
		if (0 == i % (32 * std::numeric_limits<unsigned short>::max())){
			wcout << L".";
			exe_timer_micro.set_end(high_resolution_clock::now());
			exe_timer_milli.set_end(high_resolution_clock::now());
		}
	}
	wcout << endl;
	wcout << to_wstring(exe_timer_micro.elapsed()) << L" microseconds" << endl;
	wcout << exe_timer_micro.to_wstring() << endl;

	wcout << to_wstring(exe_timer_milli.elapsed()) << L" milliseconds" << endl;
	wcout << exe_timer_milli.to_wstring() << endl;

    return;
}

Is calling a recursive class method slower than calling recursive free functions in C++ ?

While trying to make an algorithm recently, I just wondered will it be better to define and declare a recursive method outside of a class. To confirm my doubt, I wrote a small program using C++11 and tested it. It seems there isn’t any discernible difference between these two whether the function is part of a class or defined as free function. The code is as follows.

#include <chrono>
#include <iostream>
#include <string>
#include <thread>
////////////////////////////////////////////////////////////////////////////////
// Check if recursive call to calss function runs at same speed as normal function
class Factorial
{
public:
	long long get(unsigned int num)
	{
		if (num <= 1)
			return 1l;
		else
			return num*get(num - 1);
	}
};

long long factorial(unsigned int num)
{
	if (num <= 1)
		return 1l;
	else
		return num*factorial(num - 1);
}

////////////////////////////////////////////////////////////////////////////////
#pragma optimize( "", off )
void RunOOP()
{
	using namespace std;
	using namespace std::chrono;
	
	ExecutionTimer<high_resolution_clock, microseconds> exe_timer_micro(new PrintExecutionTimer());
	vector<unsigned int> num { 35, 40 };
	unsigned int iter = 2000000;
	
	vector<long long> product{ 0, 0 };
	vector<long long> result{ 0, 0 };

	wcout << L"Calling free function" << endl;
	exe_timer_micro.set_start();
	product[0] = factorial(num[0]);
	product[1] = factorial(num[1]);
	for (size_t i = 0; i < iter; i++)
	{
		result[0] = factorial(num[0]);
		result[1] = factorial(num[1]);
		if (product != result){
			product = { 0, 0 };
			break;
		}
	}
	exe_timer_micro.set_end();
	wcout << L"Factorial of " << num[0] << L" is : " << to_wstring(product[0]) << endl;
	wcout << L"Factorial of " << num[1] << L" is : " << to_wstring(product[1]) << endl;
	wcout << to_wstring(exe_timer_micro.elapsed()) << L" microseconds" << endl;
	wcout << exe_timer_micro.to_wstring() << endl;
	
	wcout << endl;
	seconds sleep_time(10);
	wcout << L"Sleeping for " << PrintExecutionTimer().to_wstring(seconds(10).count(), seconds(1)) << endl;
	std::this_thread::sleep_for(seconds(10));
	wcout << endl;

	wcout << L"Calling class method" << endl;
	exe_timer_micro.set_start();
	product[0] = Factorial().get(num[0]);
	product[1] = Factorial().get(num[1]);
	for (size_t i = 0; i < iter; i++)
	{
		result[0] = Factorial().get(num[0]);
		result[1] = Factorial().get(num[1]);
		if (product != result){
			product = { 0, 0 };
			break;
		}
	}
	exe_timer_micro.set_end();
	wcout << L"Factorial of " << num[0] << L" is : " << to_wstring(product[0]) << endl;
	wcout << L"Factorial of " << num[1] << L" is : " << to_wstring(product[1]) << endl;
	wcout << to_wstring(exe_timer_micro.elapsed()) << L" microseconds" << endl;
	wcout << exe_timer_micro.to_wstring() << endl;
}
#pragma optimize( "", on )

I used

#pragma optimize

to ensure that VS 20013 does not do any optimization for this function. To be sure of avoiding optimization, I ran it on two types of input, one by one. You can call

RunOPP

function from main to get the output. Slightly modified Code for ExecutionTimer is available at this stackoverflow thread as well as in my next blog.

As you can see, I ran the iterations around 200000 times with values 35 and 40. You can modify it as per your environment. I did not see much difference in timing between call to free function or a class method.

Enjoy timing your code to reach correct conclusion.